From f68d49c4d63fce8a663b5f0c7d6b3852dae3feef Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 29 Aug 2025 18:19:29 +0530 Subject: [PATCH 001/167] updated the migration error size attribute --- app/config/collections/projects.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/collections/projects.php b/app/config/collections/projects.php index 7fc82b7441..4fd44c7725 100644 --- a/app/config/collections/projects.php +++ b/app/config/collections/projects.php @@ -2345,7 +2345,7 @@ return [ '$id' => ID::custom('errors'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 65535, + 'size' => 131070, 'signed' => true, 'required' => true, 'default' => null, From ac604b11e3b241e504d14f14b2e09750e855c705 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 1 Sep 2025 13:13:52 +0530 Subject: [PATCH 002/167] added migration script --- src/Appwrite/Migration/Version/V23.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index d5caf2ab3c..c26c45d732 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -6,6 +6,7 @@ use Appwrite\Migration\Migration; use Exception; use Throwable; use Utopia\CLI\Console; +use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; @@ -29,6 +30,9 @@ class V23 extends Migration Console::info('Migrating databases'); $this->migrateDatabases(); + + Console::info('Migrating migration collection'); + $this->updateMigrateErrorSize(); } /** @@ -49,4 +53,26 @@ class V23 extends Migration $this->dbForProject->updateDocuments('databases', new Document(['type' => 'legacy'])); } + /** + * Update migration collection error attribute + * + * @return void + * @throws Exception|Throwable + */ + + private function updateMigrateErrorSize(): void + { + if ($this->project->getId() === 'console') { + return; + } + + $collection = Config::getParam('collections', [])['projects'] ?? []; + $migrationAttributes = $collection['migrations']['attributes']; + $attributeKey = \array_search('errors', \array_column($migrationAttributes, '$id')); + $migrationAttributes[$attributeKey]['size'] = 131070; + $migration = $this->dbForProject->getCollection('migrations'); + $migration->setAttribute('attributes', $migrationAttributes); + $this->dbForProject->updateDocument($migration->getCollection(), $migration->getId(), $migration); + $this->dbForProject->purgeCachedCollection('migrations'); + } } From 6e16340f16c7388e3e2fdfe1c73659052d392c11 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Sat, 13 Sep 2025 17:56:19 +0530 Subject: [PATCH 003/167] feat: add branch deployments to appwrite --- .../specs/open-api3-latest-console.json | 151 ++++++++++-- app/config/specs/open-api3-latest-server.json | 126 ++++++++-- app/config/specs/swagger2-latest-console.json | 159 ++++++++++-- app/config/specs/swagger2-latest-server.json | 134 ++++++++-- .../Modules/Functions/Workers/Builds.php | 12 +- .../Sites/Http/Deployments/Direct/Create.php | 231 ++++++++++++++++++ .../Platform/Modules/Sites/Services/Http.php | 2 + 7 files changed, 731 insertions(+), 84 deletions(-) create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 02d97fffc7..0de652e3fb 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -4888,7 +4888,7 @@ "x-appwrite": { "method": "getResource", "group": null, - "weight": 496, + "weight": 497, "cookies": false, "type": "", "demo": "console\/get-resource.md", @@ -28209,7 +28209,7 @@ "x-appwrite": { "method": "listRules", "group": null, - "weight": 502, + "weight": 503, "cookies": false, "type": "", "demo": "proxy\/list-rules.md", @@ -28283,7 +28283,7 @@ "x-appwrite": { "method": "createAPIRule", "group": null, - "weight": 497, + "weight": 498, "cookies": false, "type": "", "demo": "proxy\/create-api-rule.md", @@ -28350,7 +28350,7 @@ "x-appwrite": { "method": "createFunctionRule", "group": null, - "weight": 499, + "weight": 500, "cookies": false, "type": "", "demo": "proxy\/create-function-rule.md", @@ -28428,7 +28428,7 @@ "x-appwrite": { "method": "createRedirectRule", "group": null, - "weight": 500, + "weight": 501, "cookies": false, "type": "", "demo": "proxy\/create-redirect-rule.md", @@ -28541,7 +28541,7 @@ "x-appwrite": { "method": "createSiteRule", "group": null, - "weight": 498, + "weight": 499, "cookies": false, "type": "", "demo": "proxy\/create-site-rule.md", @@ -28619,7 +28619,7 @@ "x-appwrite": { "method": "getRule", "group": null, - "weight": 501, + "weight": 502, "cookies": false, "type": "", "demo": "proxy\/get-rule.md", @@ -28670,7 +28670,7 @@ "x-appwrite": { "method": "deleteRule", "group": null, - "weight": 503, + "weight": 504, "cookies": false, "type": "", "demo": "proxy\/delete-rule.md", @@ -28730,7 +28730,7 @@ "x-appwrite": { "method": "updateRuleVerification", "group": null, - "weight": 504, + "weight": 505, "cookies": false, "type": "", "demo": "proxy\/update-rule-verification.md", @@ -29085,6 +29085,103 @@ } } }, + "\/sites\/direct": { + "post": { + "summary": "Create direct deployment", + "operationId": "sitesCreateDirectDeployment", + "tags": [ + "sites" + ], + "description": "Create a deployment directly from a repository branch.", + "responses": { + "202": { + "description": "Deployment", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/deployment" + } + } + } + } + }, + "deprecated": false, + "x-appwrite": { + "method": "createDirectDeployment", + "group": "deployments", + "weight": 483, + "cookies": false, + "type": "", + "demo": "sites\/create-direct-deployment.md", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", + "rate-limit": 0, + "rate-time": 3600, + "rate-key": "url:{url},ip:{ip}", + "scope": "sites.write", + "platforms": [ + "server" + ], + "packaging": false, + "auth": { + "Project": [] + } + }, + "security": [ + { + "Project": [], + "Key": [] + } + ], + "requestBody": { + "content": { + "application\/json": { + "schema": { + "type": "object", + "properties": { + "siteId": { + "type": "string", + "description": "Site ID.", + "x-example": "" + }, + "repository": { + "type": "string", + "description": "Repository name of the template.", + "x-example": "" + }, + "owner": { + "type": "string", + "description": "The name of the owner of the template.", + "x-example": "" + }, + "rootDirectory": { + "type": "string", + "description": "Path to site code in the template repo.", + "x-example": "" + }, + "branch": { + "type": "string", + "description": "Branch to create deployment from.", + "x-example": "" + }, + "activate": { + "type": "boolean", + "description": "Automatically activate the deployment when it is finished building.", + "x-example": false + } + }, + "required": [ + "siteId", + "repository", + "owner", + "rootDirectory", + "branch" + ] + } + } + } + } + } + }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -29158,7 +29255,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 495, + "weight": 496, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -29208,7 +29305,7 @@ "x-appwrite": { "method": "listTemplates", "group": "templates", - "weight": 491, + "weight": 492, "cookies": false, "type": "", "demo": "sites\/list-templates.md", @@ -29308,7 +29405,7 @@ "x-appwrite": { "method": "getTemplate", "group": "templates", - "weight": 492, + "weight": 493, "cookies": false, "type": "", "demo": "sites\/get-template.md", @@ -29368,7 +29465,7 @@ "x-appwrite": { "method": "listUsage", "group": null, - "weight": 493, + "weight": 494, "cookies": false, "type": "", "demo": "sites\/list-usage.md", @@ -30637,7 +30734,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 484, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -30708,7 +30805,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 483, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -30770,7 +30867,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 485, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -30841,7 +30938,7 @@ "x-appwrite": { "method": "getUsage", "group": null, - "weight": 494, + "weight": 495, "cookies": false, "type": "", "demo": "sites\/get-usage.md", @@ -30923,7 +31020,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 488, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -30982,7 +31079,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 486, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -31073,7 +31170,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 487, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -31142,7 +31239,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 489, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -31233,7 +31330,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 490, + "weight": 491, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -39984,7 +40081,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 507, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -40064,7 +40161,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 505, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -40153,7 +40250,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 506, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -40213,7 +40310,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 508, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -40283,7 +40380,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 509, + "weight": 510, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 09d53dbdf0..d8d7178eb2 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -20014,6 +20014,104 @@ } } }, + "\/sites\/direct": { + "post": { + "summary": "Create direct deployment", + "operationId": "sitesCreateDirectDeployment", + "tags": [ + "sites" + ], + "description": "Create a deployment directly from a repository branch.", + "responses": { + "202": { + "description": "Deployment", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/deployment" + } + } + } + } + }, + "deprecated": false, + "x-appwrite": { + "method": "createDirectDeployment", + "group": "deployments", + "weight": 483, + "cookies": false, + "type": "", + "demo": "sites\/create-direct-deployment.md", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", + "rate-limit": 0, + "rate-time": 3600, + "rate-key": "url:{url},ip:{ip}", + "scope": "sites.write", + "platforms": [ + "server" + ], + "packaging": false, + "auth": { + "Project": [], + "Key": [] + } + }, + "security": [ + { + "Project": [], + "Key": [] + } + ], + "requestBody": { + "content": { + "application\/json": { + "schema": { + "type": "object", + "properties": { + "siteId": { + "type": "string", + "description": "Site ID.", + "x-example": "" + }, + "repository": { + "type": "string", + "description": "Repository name of the template.", + "x-example": "" + }, + "owner": { + "type": "string", + "description": "The name of the owner of the template.", + "x-example": "" + }, + "rootDirectory": { + "type": "string", + "description": "Path to site code in the template repo.", + "x-example": "" + }, + "branch": { + "type": "string", + "description": "Branch to create deployment from.", + "x-example": "" + }, + "activate": { + "type": "boolean", + "description": "Automatically activate the deployment when it is finished building.", + "x-example": false + } + }, + "required": [ + "siteId", + "repository", + "owner", + "rootDirectory", + "branch" + ] + } + } + } + } + } + }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -20088,7 +20186,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 495, + "weight": 496, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -21349,7 +21447,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 484, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -21421,7 +21519,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 483, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -21484,7 +21582,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 485, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -21556,7 +21654,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 488, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -21616,7 +21714,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 486, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -21708,7 +21806,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 487, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -21778,7 +21876,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 489, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -21870,7 +21968,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 490, + "weight": 491, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -30024,7 +30122,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 507, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -30105,7 +30203,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 505, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -30195,7 +30293,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 506, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -30256,7 +30354,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 508, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -30327,7 +30425,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 509, + "weight": 510, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 6d5721c73b..22823cd40e 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -5052,7 +5052,7 @@ "x-appwrite": { "method": "getResource", "group": null, - "weight": 496, + "weight": 497, "cookies": false, "type": "", "demo": "console\/get-resource.md", @@ -28351,7 +28351,7 @@ "x-appwrite": { "method": "listRules", "group": null, - "weight": 502, + "weight": 503, "cookies": false, "type": "", "demo": "proxy\/list-rules.md", @@ -28424,7 +28424,7 @@ "x-appwrite": { "method": "createAPIRule", "group": null, - "weight": 497, + "weight": 498, "cookies": false, "type": "", "demo": "proxy\/create-api-rule.md", @@ -28494,7 +28494,7 @@ "x-appwrite": { "method": "createFunctionRule", "group": null, - "weight": 499, + "weight": 500, "cookies": false, "type": "", "demo": "proxy\/create-function-rule.md", @@ -28577,7 +28577,7 @@ "x-appwrite": { "method": "createRedirectRule", "group": null, - "weight": 500, + "weight": 501, "cookies": false, "type": "", "demo": "proxy\/create-redirect-rule.md", @@ -28697,7 +28697,7 @@ "x-appwrite": { "method": "createSiteRule", "group": null, - "weight": 498, + "weight": 499, "cookies": false, "type": "", "demo": "proxy\/create-site-rule.md", @@ -28778,7 +28778,7 @@ "x-appwrite": { "method": "getRule", "group": null, - "weight": 501, + "weight": 502, "cookies": false, "type": "", "demo": "proxy\/get-rule.md", @@ -28831,7 +28831,7 @@ "x-appwrite": { "method": "deleteRule", "group": null, - "weight": 503, + "weight": 504, "cookies": false, "type": "", "demo": "proxy\/delete-rule.md", @@ -28891,7 +28891,7 @@ "x-appwrite": { "method": "updateRuleVerification", "group": null, - "weight": 504, + "weight": 505, "cookies": false, "type": "", "demo": "proxy\/update-rule-verification.md", @@ -29264,6 +29264,111 @@ ] } }, + "\/sites\/direct": { + "post": { + "summary": "Create direct deployment", + "operationId": "sitesCreateDirectDeployment", + "consumes": [ + "application\/json" + ], + "produces": [ + "application\/json" + ], + "tags": [ + "sites" + ], + "description": "Create a deployment directly from a repository branch.", + "responses": { + "202": { + "description": "Deployment", + "schema": { + "$ref": "#\/definitions\/deployment" + } + } + }, + "deprecated": false, + "x-appwrite": { + "method": "createDirectDeployment", + "group": "deployments", + "weight": 483, + "cookies": false, + "type": "", + "demo": "sites\/create-direct-deployment.md", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", + "rate-limit": 0, + "rate-time": 3600, + "rate-key": "url:{url},ip:{ip}", + "scope": "sites.write", + "platforms": [ + "server" + ], + "packaging": false, + "auth": { + "Project": [] + } + }, + "security": [ + { + "Project": [], + "Key": [] + } + ], + "parameters": [ + { + "name": "payload", + "in": "body", + "schema": { + "type": "object", + "properties": { + "siteId": { + "type": "string", + "description": "Site ID.", + "default": null, + "x-example": "" + }, + "repository": { + "type": "string", + "description": "Repository name of the template.", + "default": null, + "x-example": "" + }, + "owner": { + "type": "string", + "description": "The name of the owner of the template.", + "default": null, + "x-example": "" + }, + "rootDirectory": { + "type": "string", + "description": "Path to site code in the template repo.", + "default": null, + "x-example": "" + }, + "branch": { + "type": "string", + "description": "Branch to create deployment from.", + "default": null, + "x-example": "" + }, + "activate": { + "type": "boolean", + "description": "Automatically activate the deployment when it is finished building.", + "default": true, + "x-example": false + } + }, + "required": [ + "siteId", + "repository", + "owner", + "rootDirectory", + "branch" + ] + } + } + ] + } + }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -29337,7 +29442,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 495, + "weight": 496, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -29387,7 +29492,7 @@ "x-appwrite": { "method": "listTemplates", "group": "templates", - "weight": 491, + "weight": 492, "cookies": false, "type": "", "demo": "sites\/list-templates.md", @@ -29481,7 +29586,7 @@ "x-appwrite": { "method": "getTemplate", "group": "templates", - "weight": 492, + "weight": 493, "cookies": false, "type": "", "demo": "sites\/get-template.md", @@ -29539,7 +29644,7 @@ "x-appwrite": { "method": "listUsage", "group": null, - "weight": 493, + "weight": 494, "cookies": false, "type": "", "demo": "sites\/list-usage.md", @@ -30811,7 +30916,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 484, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -30882,7 +30987,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 483, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -30946,7 +31051,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 485, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -31013,7 +31118,7 @@ "x-appwrite": { "method": "getUsage", "group": null, - "weight": 494, + "weight": 495, "cookies": false, "type": "", "demo": "sites\/get-usage.md", @@ -31091,7 +31196,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 488, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -31150,7 +31255,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 486, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -31240,7 +31345,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 487, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -31307,7 +31412,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 489, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -31399,7 +31504,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 490, + "weight": 491, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -39916,7 +40021,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 507, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -39996,7 +40101,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 505, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -40080,7 +40185,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 506, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -40140,7 +40245,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 508, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -40211,7 +40316,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 509, + "weight": 510, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 98077f1050..c7a5a20c24 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -20226,6 +20226,112 @@ ] } }, + "\/sites\/direct": { + "post": { + "summary": "Create direct deployment", + "operationId": "sitesCreateDirectDeployment", + "consumes": [ + "application\/json" + ], + "produces": [ + "application\/json" + ], + "tags": [ + "sites" + ], + "description": "Create a deployment directly from a repository branch.", + "responses": { + "202": { + "description": "Deployment", + "schema": { + "$ref": "#\/definitions\/deployment" + } + } + }, + "deprecated": false, + "x-appwrite": { + "method": "createDirectDeployment", + "group": "deployments", + "weight": 483, + "cookies": false, + "type": "", + "demo": "sites\/create-direct-deployment.md", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", + "rate-limit": 0, + "rate-time": 3600, + "rate-key": "url:{url},ip:{ip}", + "scope": "sites.write", + "platforms": [ + "server" + ], + "packaging": false, + "auth": { + "Project": [], + "Key": [] + } + }, + "security": [ + { + "Project": [], + "Key": [] + } + ], + "parameters": [ + { + "name": "payload", + "in": "body", + "schema": { + "type": "object", + "properties": { + "siteId": { + "type": "string", + "description": "Site ID.", + "default": null, + "x-example": "" + }, + "repository": { + "type": "string", + "description": "Repository name of the template.", + "default": null, + "x-example": "" + }, + "owner": { + "type": "string", + "description": "The name of the owner of the template.", + "default": null, + "x-example": "" + }, + "rootDirectory": { + "type": "string", + "description": "Path to site code in the template repo.", + "default": null, + "x-example": "" + }, + "branch": { + "type": "string", + "description": "Branch to create deployment from.", + "default": null, + "x-example": "" + }, + "activate": { + "type": "boolean", + "description": "Automatically activate the deployment when it is finished building.", + "default": true, + "x-example": false + } + }, + "required": [ + "siteId", + "repository", + "owner", + "rootDirectory", + "branch" + ] + } + } + ] + } + }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -20300,7 +20406,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 495, + "weight": 496, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -21566,7 +21672,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 484, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -21638,7 +21744,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 483, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -21703,7 +21809,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 485, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -21771,7 +21877,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 488, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -21831,7 +21937,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 486, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -21922,7 +22028,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 487, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -21990,7 +22096,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 489, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -22083,7 +22189,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 490, + "weight": 491, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -30036,7 +30142,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 507, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -30117,7 +30223,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 505, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -30202,7 +30308,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 506, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -30263,7 +30369,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 508, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -30335,7 +30441,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 509, + "weight": 510, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 9547a752ef..2ac05eae77 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -311,19 +311,27 @@ class Builds extends Action $templateRepositoryName = $template->getAttribute('repositoryName', ''); $templateOwnerName = $template->getAttribute('ownerName', ''); $templateVersion = $template->getAttribute('version', ''); + $templateBranch = $template->getAttribute('branch', ''); $templateRootDirectory = $template->getAttribute('rootDirectory', ''); $templateRootDirectory = \rtrim($templateRootDirectory, '/'); $templateRootDirectory = \ltrim($templateRootDirectory, '.'); $templateRootDirectory = \ltrim($templateRootDirectory, '/'); - if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) { + if (!empty($templateRepositoryName) && !empty($templateOwnerName) && (!empty($templateVersion) || !empty($templateBranch))) { $stdout = ''; $stderr = ''; // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '-template'; - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); + + if(empty($templateVersion)) { + $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, GitHub::CLONE_TYPE_BRANCH, $tmpTemplateDirectory, $templateRootDirectory); + } else { + // True template + $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); + } + $exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr); if ($exit !== 0) { diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php new file mode 100644 index 0000000000..092a7702df --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php @@ -0,0 +1,231 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/sites/direct') + ->desc('Create direct deployment') + ->groups(['api', 'sites']) + ->label('scope', 'sites.write') + ->label('resourceType', RESOURCE_TYPE_SITES) + ->label('event', 'sites.[siteId].deployments.[deploymentId].create') + ->label('audits.event', 'deployment.create') + ->label('audits.resource', 'site/{request.siteId}') + ->label('sdk', new Method( + namespace: 'sites', + group: 'deployments', + name: 'createDirectDeployment', + description: <<param('siteId', '', new UID(), 'Site ID.') + ->param('repository', '', new Text(128, 0), 'Repository name of the template.') + ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') + ->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') + ->param('branch', '', new Text(128, 0), 'Branch to create deployment from.') + ->param('activate', true, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) + ->inject('request') + ->inject('response') + ->inject('dbForProject') + ->inject('dbForPlatform') + ->inject('project') + ->inject('queueForEvents') + ->inject('queueForBuilds') + ->inject('gitHub') + ->callback($this->action(...)); + } + + public function action( + string $siteId, + string $repository, + string $owner, + string $rootDirectory, + string $branch, + bool $activate, + Request $request, + Response $response, + Database $dbForProject, + Database $dbForPlatform, + Document $project, + Event $queueForEvents, + Build $queueForBuilds, + GitHub $github + ) { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $template = new Document([ + 'repositoryName' => $repository, + 'ownerName' => $owner, + 'rootDirectory' => $rootDirectory, + 'branch' => $branch + ]); + + + if (!empty($site->getAttribute('providerRepositoryId'))) { + $installation = $dbForPlatform->getDocument('installations', $site->getAttribute('installationId')); + + $deployment = $this->redeployVcsSite( + request: $request, + site: $site, + project: $project, + installation: $installation, + dbForProject: $dbForProject, + dbForPlatform: $dbForPlatform, + queueForBuilds: $queueForBuilds, + template: $template, + github: $github, + activate: $activate, + ); + + $queueForEvents + ->setParam('siteId', $site->getId()) + ->setParam('deploymentId', $deployment->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); + + return; + } + + $branchUrl = "https://github.com/$owner/$repository/tree/$branch"; + $repositoryUrl = "https://github.com/$owner/$repository"; + + try { + $commitDetails = $github->getLatestCommit($owner, $repository, $branch); + } catch (\Throwable $error) { + // Ignore; deployment can continue + } + + $commands = []; + if (!empty($site->getAttribute('installCommand', ''))) { + $commands[] = $site->getAttribute('installCommand', ''); + } + if (!empty($site->getAttribute('buildCommand', ''))) { + $commands[] = $site->getAttribute('buildCommand', ''); + } + + $deploymentId = ID::unique(); + $deployment = $dbForProject->createDocument('deployments', new Document([ + '$id' => $deploymentId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceId' => $site->getId(), + 'resourceInternalId' => $site->getSequence(), + 'resourceType' => 'sites', + 'buildCommands' => \implode(' && ', $commands), + 'buildOutput' => $site->getAttribute('outputDirectory', ''), + 'adapter' => $site->getAttribute('adapter', ''), + 'fallbackFile' => $site->getAttribute('fallbackFile', ''), + 'providerRepositoryName' => $repository, + 'providerRepositoryOwner' => $owner, + 'providerRepositoryUrl' => $repositoryUrl, + 'providerBranchUrl' => $branchUrl, + 'providerBranch' => $branch, + 'providerCommitHash' => $commitDetails['commitHash'] ?? '', + 'providerCommitAuthorUrl' => $commitDetails['commitAuthorUrl'] ?? '', + 'providerCommitAuthor' => $commitDetails['commitAuthor'] ?? '', + 'providerCommitMessage' => mb_strimwidth($commitDetails['commitMessage'] ?? '', 0, 255, '...'), + 'providerCommitUrl' => $commitDetails['commitUrl'] ?? '', + 'type' => 'vcs', + 'activate' => $activate, + ])); + + $site = $site + ->setAttribute('latestDeploymentId', $deployment->getId()) + ->setAttribute('latestDeploymentInternalId', $deployment->getSequence()) + ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) + ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); + $dbForProject->updateDocument('sites', $site->getId(), $site); + + $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); + $domain = ID::unique() . "." . $sitesDomain; + + // TODO: @christyjacob remove once we migrate the rules in 1.7.x + $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); + + Authorization::skip( + fn () => $dbForPlatform->createDocument('rules', new Document([ + '$id' => $ruleId, + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getSequence(), + 'domain' => $domain, + 'type' => 'deployment', + 'trigger' => 'deployment', + 'deploymentId' => $deployment->isEmpty() ? '' : $deployment->getId(), + 'deploymentInternalId' => $deployment->isEmpty() ? '' : $deployment->getSequence(), + 'deploymentResourceType' => 'site', + 'deploymentResourceId' => $site->getId(), + 'deploymentResourceInternalId' => $site->getSequence(), + 'status' => 'verified', + 'certificateId' => '', + 'owner' => 'Appwrite', + 'region' => $project->getAttribute('region') + ])) + ); + + $queueForBuilds + ->setType(BUILD_TYPE_DEPLOYMENT) + ->setResource($site) + ->setDeployment($deployment) + ->setTemplate($template); + + $queueForEvents + ->setParam('siteId', $site->getId()) + ->setParam('deploymentId', $deployment->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index 6bd151f97e..f19b9b6d71 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -6,6 +6,7 @@ use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Download\Get as DownloadDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Duplicate\Create as CreateDuplicateDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Status\Update as UpdateDeploymentStatus; use Appwrite\Platform\Modules\Sites\Http\Deployments\Template\Create as CreateTemplateDeployment; @@ -60,6 +61,7 @@ class Http extends Service $this->addAction(DownloadDeployment::getName(), new DownloadDeployment()); $this->addAction(CreateDuplicateDeployment::getName(), new CreateDuplicateDeployment()); $this->addAction(UpdateDeploymentStatus::getName(), new UpdateDeploymentStatus()); + $this->addAction(CreateDirectDeployment::getName(), new CreateDirectDeployment()); // Logs $this->addAction(GetLog::getName(), new GetLog()); From 4858317891faa2a5a0bdcaf4ea3f976d223ae125 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Sat, 13 Sep 2025 18:02:13 +0530 Subject: [PATCH 004/167] fix: format, lints --- .../Platform/Modules/Functions/Workers/Builds.php | 4 ++-- .../Modules/Sites/Http/Deployments/Direct/Create.php | 8 ++++---- src/Appwrite/Platform/Modules/Sites/Services/Http.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 2ac05eae77..62ee96da47 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -324,8 +324,8 @@ class Builds extends Action // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '-template'; - - if(empty($templateVersion)) { + + if (empty($templateVersion)) { $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, GitHub::CLONE_TYPE_BRANCH, $tmpTemplateDirectory, $templateRootDirectory); } else { // True template diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php index 092a7702df..d1df994149 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php @@ -106,7 +106,7 @@ class Create extends Base 'rootDirectory' => $rootDirectory, 'branch' => $branch ]); - + if (!empty($site->getAttribute('providerRepositoryId'))) { $installation = $dbForPlatform->getDocument('installations', $site->getAttribute('installationId')); @@ -137,11 +137,11 @@ class Create extends Base $branchUrl = "https://github.com/$owner/$repository/tree/$branch"; $repositoryUrl = "https://github.com/$owner/$repository"; - + try { - $commitDetails = $github->getLatestCommit($owner, $repository, $branch); + $commitDetails = $github->getLatestCommit($owner, $repository, $branch); } catch (\Throwable $error) { - // Ignore; deployment can continue + // Ignore; deployment can continue } $commands = []; diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index f19b9b6d71..437356d4e2 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -4,9 +4,9 @@ namespace Appwrite\Platform\Modules\Sites\Services; use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Download\Get as DownloadDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Duplicate\Create as CreateDuplicateDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Status\Update as UpdateDeploymentStatus; use Appwrite\Platform\Modules\Sites\Http\Deployments\Template\Create as CreateTemplateDeployment; From 2b1e3bd9477941431f3f5055ea118b1fe62e9067 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Sun, 14 Sep 2025 15:15:44 +0530 Subject: [PATCH 005/167] delete the new route and just do it in template route --- .../Http/Deployments/Template/Create.php | 26 ++++++++++++++++--- .../Modules/Functions/Workers/Builds.php | 13 +++------- .../Http/Deployments/Template/Create.php | 26 ++++++++++++++++--- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php index 4d93c8e8cd..885e23bfa1 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php @@ -65,7 +65,9 @@ class Create extends Base ->param('repository', '', new Text(128, 0), 'Repository name of the template.') ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') ->param('rootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.') - ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.') + ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) + ->param('type', '', new Text(128, 0), 'Type for the reference provided. Can be commit, branch, or version', true) + ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) ->inject('request') ->inject('response') @@ -84,6 +86,8 @@ class Create extends Base string $owner, string $rootDirectory, string $version, + string $type, + string $reference, bool $activate, Request $request, Response $response, @@ -100,11 +104,22 @@ class Create extends Base throw new Exception(Exception::FUNCTION_NOT_FOUND); } + if (empty($version) && empty($type) && empty($reference)) { + throw new Exception("Either version or type & reference must be provided"); + } + + $referenceType = !empty($version) ? GitHub::CLONE_TYPE_TAG : $type; + $referenceValue = !empty($version) ? $version : $reference; + + $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$referenceValue" : ""; + $repositoryUrl = "https://github.com/$owner/$repository"; + $template = new Document([ 'repositoryName' => $repository, 'ownerName' => $owner, 'rootDirectory' => $rootDirectory, - 'version' => $version + 'referenceType' => $referenceType, + 'referenceValue' => $referenceValue, ]); if (!empty($function->getAttribute('providerRepositoryId'))) { @@ -146,7 +161,12 @@ class Create extends Base 'resourceType' => 'functions', 'entrypoint' => $function->getAttribute('entrypoint', ''), 'buildCommands' => $function->getAttribute('commands', ''), - 'type' => 'manual', + 'providerRepositoryName' => $repository, + 'providerRepositoryOwner' => $owner, + 'providerRepositoryUrl' => $repositoryUrl, + 'providerBranchUrl' => $branchUrl, + 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $referenceValue : '', + 'type' => 'vcs', 'activate' => $activate, ])); diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 62ee96da47..4bb49a42c8 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -310,27 +310,22 @@ class Builds extends Action // Non-VCS + Template $templateRepositoryName = $template->getAttribute('repositoryName', ''); $templateOwnerName = $template->getAttribute('ownerName', ''); - $templateVersion = $template->getAttribute('version', ''); - $templateBranch = $template->getAttribute('branch', ''); + $templateReferenceType = $template->getAttribute('referenceType', ''); + $templateReferenceValue = $template->getAttribute('referenceValue', ''); $templateRootDirectory = $template->getAttribute('rootDirectory', ''); $templateRootDirectory = \rtrim($templateRootDirectory, '/'); $templateRootDirectory = \ltrim($templateRootDirectory, '.'); $templateRootDirectory = \ltrim($templateRootDirectory, '/'); - if (!empty($templateRepositoryName) && !empty($templateOwnerName) && (!empty($templateVersion) || !empty($templateBranch))) { + if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateReferenceType) && !empty($templateReferenceValue)) { $stdout = ''; $stderr = ''; // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '-template'; - if (empty($templateVersion)) { - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, GitHub::CLONE_TYPE_BRANCH, $tmpTemplateDirectory, $templateRootDirectory); - } else { - // True template - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); - } + $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateReferenceValue, $templateReferenceType, $tmpTemplateDirectory, $templateRootDirectory); $exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index a2040d830b..0799e0b51f 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -67,7 +67,9 @@ class Create extends Base ->param('repository', '', new Text(128, 0), 'Repository name of the template.') ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') ->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') - ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the site template.') + ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) + ->param('type', '', new Text(128, 0), 'Type for the reference provided. Can be commit, branch, or version', true) + ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) ->inject('request') ->inject('response') @@ -86,6 +88,8 @@ class Create extends Base string $owner, string $rootDirectory, string $version, + string $type, + string $reference, bool $activate, Request $request, Response $response, @@ -102,11 +106,22 @@ class Create extends Base throw new Exception(Exception::SITE_NOT_FOUND); } + if (empty($version) && empty($type) && empty($reference)) { + throw new Exception("Either version or type & reference must be provided"); + } + + $referenceType = !empty($version) ? GitHub::CLONE_TYPE_TAG : $type; + $referenceValue = !empty($version) ? $version : $reference; + + $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$referenceValue" : ""; + $repositoryUrl = "https://github.com/$owner/$repository"; + $template = new Document([ 'repositoryName' => $repository, 'ownerName' => $owner, 'rootDirectory' => $rootDirectory, - 'version' => $version + 'referenceType' => $referenceType, + 'referenceValue' => $referenceValue ]); if (!empty($site->getAttribute('providerRepositoryId'))) { @@ -157,9 +172,14 @@ class Create extends Base 'resourceType' => 'sites', 'buildCommands' => \implode(' && ', $commands), 'buildOutput' => $site->getAttribute('outputDirectory', ''), + 'providerRepositoryName' => $repository, + 'providerRepositoryOwner' => $owner, + 'providerRepositoryUrl' => $repositoryUrl, + 'providerBranchUrl' => $branchUrl, + 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $referenceValue : '', 'adapter' => $site->getAttribute('adapter', ''), 'fallbackFile' => $site->getAttribute('fallbackFile', ''), - 'type' => 'manual', + 'type' => 'vcs', 'activate' => $activate, ])); From cb03bfe74ccd1ac43737053113b27a82e8bd3cbd Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Sun, 14 Sep 2025 15:22:51 +0530 Subject: [PATCH 006/167] specs and sdk --- .../specs/open-api3-latest-console.json | 179 ++++---------- app/config/specs/open-api3-latest-server.json | 154 +++--------- app/config/specs/swagger2-latest-console.json | 195 +++++---------- app/config/specs/swagger2-latest-server.json | 170 ++++--------- .../Sites/Http/Deployments/Direct/Create.php | 231 ------------------ .../Platform/Modules/Sites/Services/Http.php | 2 - 6 files changed, 186 insertions(+), 745 deletions(-) delete mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 0de652e3fb..96cec5c5a6 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -4888,7 +4888,7 @@ "x-appwrite": { "method": "getResource", "group": null, - "weight": 497, + "weight": 496, "cookies": false, "type": "", "demo": "console\/get-resource.md", @@ -12932,6 +12932,16 @@ "description": "Version (tag) for the repo linked to the function template.", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -12941,8 +12951,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -28209,7 +28218,7 @@ "x-appwrite": { "method": "listRules", "group": null, - "weight": 503, + "weight": 502, "cookies": false, "type": "", "demo": "proxy\/list-rules.md", @@ -28283,7 +28292,7 @@ "x-appwrite": { "method": "createAPIRule", "group": null, - "weight": 498, + "weight": 497, "cookies": false, "type": "", "demo": "proxy\/create-api-rule.md", @@ -28350,7 +28359,7 @@ "x-appwrite": { "method": "createFunctionRule", "group": null, - "weight": 500, + "weight": 499, "cookies": false, "type": "", "demo": "proxy\/create-function-rule.md", @@ -28428,7 +28437,7 @@ "x-appwrite": { "method": "createRedirectRule", "group": null, - "weight": 501, + "weight": 500, "cookies": false, "type": "", "demo": "proxy\/create-redirect-rule.md", @@ -28541,7 +28550,7 @@ "x-appwrite": { "method": "createSiteRule", "group": null, - "weight": 499, + "weight": 498, "cookies": false, "type": "", "demo": "proxy\/create-site-rule.md", @@ -28619,7 +28628,7 @@ "x-appwrite": { "method": "getRule", "group": null, - "weight": 502, + "weight": 501, "cookies": false, "type": "", "demo": "proxy\/get-rule.md", @@ -28670,7 +28679,7 @@ "x-appwrite": { "method": "deleteRule", "group": null, - "weight": 504, + "weight": 503, "cookies": false, "type": "", "demo": "proxy\/delete-rule.md", @@ -28730,7 +28739,7 @@ "x-appwrite": { "method": "updateRuleVerification", "group": null, - "weight": 505, + "weight": 504, "cookies": false, "type": "", "demo": "proxy\/update-rule-verification.md", @@ -29085,103 +29094,6 @@ } } }, - "\/sites\/direct": { - "post": { - "summary": "Create direct deployment", - "operationId": "sitesCreateDirectDeployment", - "tags": [ - "sites" - ], - "description": "Create a deployment directly from a repository branch.", - "responses": { - "202": { - "description": "Deployment", - "content": { - "application\/json": { - "schema": { - "$ref": "#\/components\/schemas\/deployment" - } - } - } - } - }, - "deprecated": false, - "x-appwrite": { - "method": "createDirectDeployment", - "group": "deployments", - "weight": 483, - "cookies": false, - "type": "", - "demo": "sites\/create-direct-deployment.md", - "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", - "rate-limit": 0, - "rate-time": 3600, - "rate-key": "url:{url},ip:{ip}", - "scope": "sites.write", - "platforms": [ - "server" - ], - "packaging": false, - "auth": { - "Project": [] - } - }, - "security": [ - { - "Project": [], - "Key": [] - } - ], - "requestBody": { - "content": { - "application\/json": { - "schema": { - "type": "object", - "properties": { - "siteId": { - "type": "string", - "description": "Site ID.", - "x-example": "" - }, - "repository": { - "type": "string", - "description": "Repository name of the template.", - "x-example": "" - }, - "owner": { - "type": "string", - "description": "The name of the owner of the template.", - "x-example": "" - }, - "rootDirectory": { - "type": "string", - "description": "Path to site code in the template repo.", - "x-example": "" - }, - "branch": { - "type": "string", - "description": "Branch to create deployment from.", - "x-example": "" - }, - "activate": { - "type": "boolean", - "description": "Automatically activate the deployment when it is finished building.", - "x-example": false - } - }, - "required": [ - "siteId", - "repository", - "owner", - "rootDirectory", - "branch" - ] - } - } - } - } - } - }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -29255,7 +29167,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 496, + "weight": 495, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -29305,7 +29217,7 @@ "x-appwrite": { "method": "listTemplates", "group": "templates", - "weight": 492, + "weight": 491, "cookies": false, "type": "", "demo": "sites\/list-templates.md", @@ -29405,7 +29317,7 @@ "x-appwrite": { "method": "getTemplate", "group": "templates", - "weight": 493, + "weight": 492, "cookies": false, "type": "", "demo": "sites\/get-template.md", @@ -29465,7 +29377,7 @@ "x-appwrite": { "method": "listUsage", "group": null, - "weight": 494, + "weight": 493, "cookies": false, "type": "", "demo": "sites\/list-usage.md", @@ -30304,9 +30216,19 @@ }, "version": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", + "description": "Version (tag) for the repo linked to the function template.", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -30316,8 +30238,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -30734,7 +30655,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 485, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -30805,7 +30726,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 484, + "weight": 483, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -30867,7 +30788,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 486, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -30938,7 +30859,7 @@ "x-appwrite": { "method": "getUsage", "group": null, - "weight": 495, + "weight": 494, "cookies": false, "type": "", "demo": "sites\/get-usage.md", @@ -31020,7 +30941,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 489, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -31079,7 +31000,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 487, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -31170,7 +31091,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 488, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -31239,7 +31160,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 490, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -31330,7 +31251,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 491, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -40081,7 +40002,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 508, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -40161,7 +40082,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 506, + "weight": 505, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -40250,7 +40171,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 507, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -40310,7 +40231,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 509, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -40380,7 +40301,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 510, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index d8d7178eb2..3a1afab16b 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -11714,6 +11714,16 @@ "description": "Version (tag) for the repo linked to the function template.", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -11723,8 +11733,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -20014,104 +20023,6 @@ } } }, - "\/sites\/direct": { - "post": { - "summary": "Create direct deployment", - "operationId": "sitesCreateDirectDeployment", - "tags": [ - "sites" - ], - "description": "Create a deployment directly from a repository branch.", - "responses": { - "202": { - "description": "Deployment", - "content": { - "application\/json": { - "schema": { - "$ref": "#\/components\/schemas\/deployment" - } - } - } - } - }, - "deprecated": false, - "x-appwrite": { - "method": "createDirectDeployment", - "group": "deployments", - "weight": 483, - "cookies": false, - "type": "", - "demo": "sites\/create-direct-deployment.md", - "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", - "rate-limit": 0, - "rate-time": 3600, - "rate-key": "url:{url},ip:{ip}", - "scope": "sites.write", - "platforms": [ - "server" - ], - "packaging": false, - "auth": { - "Project": [], - "Key": [] - } - }, - "security": [ - { - "Project": [], - "Key": [] - } - ], - "requestBody": { - "content": { - "application\/json": { - "schema": { - "type": "object", - "properties": { - "siteId": { - "type": "string", - "description": "Site ID.", - "x-example": "" - }, - "repository": { - "type": "string", - "description": "Repository name of the template.", - "x-example": "" - }, - "owner": { - "type": "string", - "description": "The name of the owner of the template.", - "x-example": "" - }, - "rootDirectory": { - "type": "string", - "description": "Path to site code in the template repo.", - "x-example": "" - }, - "branch": { - "type": "string", - "description": "Branch to create deployment from.", - "x-example": "" - }, - "activate": { - "type": "boolean", - "description": "Automatically activate the deployment when it is finished building.", - "x-example": false - } - }, - "required": [ - "siteId", - "repository", - "owner", - "rootDirectory", - "branch" - ] - } - } - } - } - } - }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -20186,7 +20097,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 496, + "weight": 495, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -21012,9 +20923,19 @@ }, "version": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", + "description": "Version (tag) for the repo linked to the function template.", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -21024,8 +20945,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -21447,7 +21367,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 485, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -21519,7 +21439,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 484, + "weight": 483, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -21582,7 +21502,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 486, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -21654,7 +21574,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 489, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -21714,7 +21634,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 487, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -21806,7 +21726,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 488, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -21876,7 +21796,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 490, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -21968,7 +21888,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 491, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -30122,7 +30042,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 508, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -30203,7 +30123,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 506, + "weight": 505, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -30293,7 +30213,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 507, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -30354,7 +30274,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 509, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -30425,7 +30345,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 510, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 22823cd40e..27604767b9 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -5052,7 +5052,7 @@ "x-appwrite": { "method": "getResource", "group": null, - "weight": 497, + "weight": 496, "cookies": false, "type": "", "demo": "console\/get-resource.md", @@ -12928,9 +12928,21 @@ "version": { "type": "string", "description": "Version (tag) for the repo linked to the function template.", - "default": null, + "default": "", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "default": "", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": "", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -12941,8 +12953,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -28351,7 +28362,7 @@ "x-appwrite": { "method": "listRules", "group": null, - "weight": 503, + "weight": 502, "cookies": false, "type": "", "demo": "proxy\/list-rules.md", @@ -28424,7 +28435,7 @@ "x-appwrite": { "method": "createAPIRule", "group": null, - "weight": 498, + "weight": 497, "cookies": false, "type": "", "demo": "proxy\/create-api-rule.md", @@ -28494,7 +28505,7 @@ "x-appwrite": { "method": "createFunctionRule", "group": null, - "weight": 500, + "weight": 499, "cookies": false, "type": "", "demo": "proxy\/create-function-rule.md", @@ -28577,7 +28588,7 @@ "x-appwrite": { "method": "createRedirectRule", "group": null, - "weight": 501, + "weight": 500, "cookies": false, "type": "", "demo": "proxy\/create-redirect-rule.md", @@ -28697,7 +28708,7 @@ "x-appwrite": { "method": "createSiteRule", "group": null, - "weight": 499, + "weight": 498, "cookies": false, "type": "", "demo": "proxy\/create-site-rule.md", @@ -28778,7 +28789,7 @@ "x-appwrite": { "method": "getRule", "group": null, - "weight": 502, + "weight": 501, "cookies": false, "type": "", "demo": "proxy\/get-rule.md", @@ -28831,7 +28842,7 @@ "x-appwrite": { "method": "deleteRule", "group": null, - "weight": 504, + "weight": 503, "cookies": false, "type": "", "demo": "proxy\/delete-rule.md", @@ -28891,7 +28902,7 @@ "x-appwrite": { "method": "updateRuleVerification", "group": null, - "weight": 505, + "weight": 504, "cookies": false, "type": "", "demo": "proxy\/update-rule-verification.md", @@ -29264,111 +29275,6 @@ ] } }, - "\/sites\/direct": { - "post": { - "summary": "Create direct deployment", - "operationId": "sitesCreateDirectDeployment", - "consumes": [ - "application\/json" - ], - "produces": [ - "application\/json" - ], - "tags": [ - "sites" - ], - "description": "Create a deployment directly from a repository branch.", - "responses": { - "202": { - "description": "Deployment", - "schema": { - "$ref": "#\/definitions\/deployment" - } - } - }, - "deprecated": false, - "x-appwrite": { - "method": "createDirectDeployment", - "group": "deployments", - "weight": 483, - "cookies": false, - "type": "", - "demo": "sites\/create-direct-deployment.md", - "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", - "rate-limit": 0, - "rate-time": 3600, - "rate-key": "url:{url},ip:{ip}", - "scope": "sites.write", - "platforms": [ - "server" - ], - "packaging": false, - "auth": { - "Project": [] - } - }, - "security": [ - { - "Project": [], - "Key": [] - } - ], - "parameters": [ - { - "name": "payload", - "in": "body", - "schema": { - "type": "object", - "properties": { - "siteId": { - "type": "string", - "description": "Site ID.", - "default": null, - "x-example": "" - }, - "repository": { - "type": "string", - "description": "Repository name of the template.", - "default": null, - "x-example": "" - }, - "owner": { - "type": "string", - "description": "The name of the owner of the template.", - "default": null, - "x-example": "" - }, - "rootDirectory": { - "type": "string", - "description": "Path to site code in the template repo.", - "default": null, - "x-example": "" - }, - "branch": { - "type": "string", - "description": "Branch to create deployment from.", - "default": null, - "x-example": "" - }, - "activate": { - "type": "boolean", - "description": "Automatically activate the deployment when it is finished building.", - "default": true, - "x-example": false - } - }, - "required": [ - "siteId", - "repository", - "owner", - "rootDirectory", - "branch" - ] - } - } - ] - } - }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -29442,7 +29348,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 496, + "weight": 495, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -29492,7 +29398,7 @@ "x-appwrite": { "method": "listTemplates", "group": "templates", - "weight": 492, + "weight": 491, "cookies": false, "type": "", "demo": "sites\/list-templates.md", @@ -29586,7 +29492,7 @@ "x-appwrite": { "method": "getTemplate", "group": "templates", - "weight": 493, + "weight": 492, "cookies": false, "type": "", "demo": "sites\/get-template.md", @@ -29644,7 +29550,7 @@ "x-appwrite": { "method": "listUsage", "group": null, - "weight": 494, + "weight": 493, "cookies": false, "type": "", "demo": "sites\/list-usage.md", @@ -30490,10 +30396,22 @@ }, "version": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", - "default": null, + "description": "Version (tag) for the repo linked to the function template.", + "default": "", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "default": "", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": "", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -30504,8 +30422,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -30916,7 +30833,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 485, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -30987,7 +30904,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 484, + "weight": 483, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -31051,7 +30968,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 486, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -31118,7 +31035,7 @@ "x-appwrite": { "method": "getUsage", "group": null, - "weight": 495, + "weight": 494, "cookies": false, "type": "", "demo": "sites\/get-usage.md", @@ -31196,7 +31113,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 489, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -31255,7 +31172,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 487, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -31345,7 +31262,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 488, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -31412,7 +31329,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 490, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -31504,7 +31421,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 491, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -40021,7 +39938,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 508, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -40101,7 +40018,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 506, + "weight": 505, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -40185,7 +40102,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 507, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -40245,7 +40162,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 509, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -40316,7 +40233,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 510, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index c7a5a20c24..a13c8324a4 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -11735,9 +11735,21 @@ "version": { "type": "string", "description": "Version (tag) for the repo linked to the function template.", - "default": null, + "default": "", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "default": "", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": "", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -11748,8 +11760,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -20226,112 +20237,6 @@ ] } }, - "\/sites\/direct": { - "post": { - "summary": "Create direct deployment", - "operationId": "sitesCreateDirectDeployment", - "consumes": [ - "application\/json" - ], - "produces": [ - "application\/json" - ], - "tags": [ - "sites" - ], - "description": "Create a deployment directly from a repository branch.", - "responses": { - "202": { - "description": "Deployment", - "schema": { - "$ref": "#\/definitions\/deployment" - } - } - }, - "deprecated": false, - "x-appwrite": { - "method": "createDirectDeployment", - "group": "deployments", - "weight": 483, - "cookies": false, - "type": "", - "demo": "sites\/create-direct-deployment.md", - "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a deployment directly from a repository branch.", - "rate-limit": 0, - "rate-time": 3600, - "rate-key": "url:{url},ip:{ip}", - "scope": "sites.write", - "platforms": [ - "server" - ], - "packaging": false, - "auth": { - "Project": [], - "Key": [] - } - }, - "security": [ - { - "Project": [], - "Key": [] - } - ], - "parameters": [ - { - "name": "payload", - "in": "body", - "schema": { - "type": "object", - "properties": { - "siteId": { - "type": "string", - "description": "Site ID.", - "default": null, - "x-example": "" - }, - "repository": { - "type": "string", - "description": "Repository name of the template.", - "default": null, - "x-example": "" - }, - "owner": { - "type": "string", - "description": "The name of the owner of the template.", - "default": null, - "x-example": "" - }, - "rootDirectory": { - "type": "string", - "description": "Path to site code in the template repo.", - "default": null, - "x-example": "" - }, - "branch": { - "type": "string", - "description": "Branch to create deployment from.", - "default": null, - "x-example": "" - }, - "activate": { - "type": "boolean", - "description": "Automatically activate the deployment when it is finished building.", - "default": true, - "x-example": false - } - }, - "required": [ - "siteId", - "repository", - "owner", - "rootDirectory", - "branch" - ] - } - } - ] - } - }, "\/sites\/frameworks": { "get": { "summary": "List frameworks", @@ -20406,7 +20311,7 @@ "x-appwrite": { "method": "listSpecifications", "group": "frameworks", - "weight": 496, + "weight": 495, "cookies": false, "type": "", "demo": "sites\/list-specifications.md", @@ -21241,10 +21146,22 @@ }, "version": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", - "default": null, + "description": "Version (tag) for the repo linked to the function template.", + "default": "", "x-example": "" }, + "type": { + "type": "string", + "description": "Type for the reference provided. Can be commit, branch, or version", + "default": "", + "x-example": "" + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": "", + "x-example": "" + }, "activate": { "type": "boolean", "description": "Automatically activate the deployment when it is finished building.", @@ -21255,8 +21172,7 @@ "required": [ "repository", "owner", - "rootDirectory", - "version" + "rootDirectory" ] } } @@ -21672,7 +21588,7 @@ "x-appwrite": { "method": "listLogs", "group": "logs", - "weight": 485, + "weight": 484, "cookies": false, "type": "", "demo": "sites\/list-logs.md", @@ -21744,7 +21660,7 @@ "x-appwrite": { "method": "getLog", "group": "logs", - "weight": 484, + "weight": 483, "cookies": false, "type": "", "demo": "sites\/get-log.md", @@ -21809,7 +21725,7 @@ "x-appwrite": { "method": "deleteLog", "group": "logs", - "weight": 486, + "weight": 485, "cookies": false, "type": "", "demo": "sites\/delete-log.md", @@ -21877,7 +21793,7 @@ "x-appwrite": { "method": "listVariables", "group": "variables", - "weight": 489, + "weight": 488, "cookies": false, "type": "", "demo": "sites\/list-variables.md", @@ -21937,7 +21853,7 @@ "x-appwrite": { "method": "createVariable", "group": "variables", - "weight": 487, + "weight": 486, "cookies": false, "type": "", "demo": "sites\/create-variable.md", @@ -22028,7 +21944,7 @@ "x-appwrite": { "method": "getVariable", "group": "variables", - "weight": 488, + "weight": 487, "cookies": false, "type": "", "demo": "sites\/get-variable.md", @@ -22096,7 +22012,7 @@ "x-appwrite": { "method": "updateVariable", "group": "variables", - "weight": 490, + "weight": 489, "cookies": false, "type": "", "demo": "sites\/update-variable.md", @@ -22189,7 +22105,7 @@ "x-appwrite": { "method": "deleteVariable", "group": "variables", - "weight": 491, + "weight": 490, "cookies": false, "type": "", "demo": "sites\/delete-variable.md", @@ -30142,7 +30058,7 @@ "x-appwrite": { "method": "list", "group": "files", - "weight": 508, + "weight": 507, "cookies": false, "type": "", "demo": "tokens\/list.md", @@ -30223,7 +30139,7 @@ "x-appwrite": { "method": "createFileToken", "group": "files", - "weight": 506, + "weight": 505, "cookies": false, "type": "", "demo": "tokens\/create-file-token.md", @@ -30308,7 +30224,7 @@ "x-appwrite": { "method": "get", "group": "tokens", - "weight": 507, + "weight": 506, "cookies": false, "type": "", "demo": "tokens\/get.md", @@ -30369,7 +30285,7 @@ "x-appwrite": { "method": "update", "group": "tokens", - "weight": 509, + "weight": 508, "cookies": false, "type": "", "demo": "tokens\/update.md", @@ -30441,7 +30357,7 @@ "x-appwrite": { "method": "delete", "group": "tokens", - "weight": 510, + "weight": 509, "cookies": false, "type": "", "demo": "tokens\/delete.md", diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php deleted file mode 100644 index d1df994149..0000000000 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php +++ /dev/null @@ -1,231 +0,0 @@ -setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) - ->setHttpPath('/v1/sites/direct') - ->desc('Create direct deployment') - ->groups(['api', 'sites']) - ->label('scope', 'sites.write') - ->label('resourceType', RESOURCE_TYPE_SITES) - ->label('event', 'sites.[siteId].deployments.[deploymentId].create') - ->label('audits.event', 'deployment.create') - ->label('audits.resource', 'site/{request.siteId}') - ->label('sdk', new Method( - namespace: 'sites', - group: 'deployments', - name: 'createDirectDeployment', - description: <<param('siteId', '', new UID(), 'Site ID.') - ->param('repository', '', new Text(128, 0), 'Repository name of the template.') - ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') - ->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') - ->param('branch', '', new Text(128, 0), 'Branch to create deployment from.') - ->param('activate', true, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) - ->inject('request') - ->inject('response') - ->inject('dbForProject') - ->inject('dbForPlatform') - ->inject('project') - ->inject('queueForEvents') - ->inject('queueForBuilds') - ->inject('gitHub') - ->callback($this->action(...)); - } - - public function action( - string $siteId, - string $repository, - string $owner, - string $rootDirectory, - string $branch, - bool $activate, - Request $request, - Response $response, - Database $dbForProject, - Database $dbForPlatform, - Document $project, - Event $queueForEvents, - Build $queueForBuilds, - GitHub $github - ) { - $site = $dbForProject->getDocument('sites', $siteId); - - if ($site->isEmpty()) { - throw new Exception(Exception::SITE_NOT_FOUND); - } - - $template = new Document([ - 'repositoryName' => $repository, - 'ownerName' => $owner, - 'rootDirectory' => $rootDirectory, - 'branch' => $branch - ]); - - - if (!empty($site->getAttribute('providerRepositoryId'))) { - $installation = $dbForPlatform->getDocument('installations', $site->getAttribute('installationId')); - - $deployment = $this->redeployVcsSite( - request: $request, - site: $site, - project: $project, - installation: $installation, - dbForProject: $dbForProject, - dbForPlatform: $dbForPlatform, - queueForBuilds: $queueForBuilds, - template: $template, - github: $github, - activate: $activate, - ); - - $queueForEvents - ->setParam('siteId', $site->getId()) - ->setParam('deploymentId', $deployment->getId()); - - $response - ->setStatusCode(Response::STATUS_CODE_ACCEPTED) - ->dynamic($deployment, Response::MODEL_DEPLOYMENT); - - return; - } - - $branchUrl = "https://github.com/$owner/$repository/tree/$branch"; - $repositoryUrl = "https://github.com/$owner/$repository"; - - try { - $commitDetails = $github->getLatestCommit($owner, $repository, $branch); - } catch (\Throwable $error) { - // Ignore; deployment can continue - } - - $commands = []; - if (!empty($site->getAttribute('installCommand', ''))) { - $commands[] = $site->getAttribute('installCommand', ''); - } - if (!empty($site->getAttribute('buildCommand', ''))) { - $commands[] = $site->getAttribute('buildCommand', ''); - } - - $deploymentId = ID::unique(); - $deployment = $dbForProject->createDocument('deployments', new Document([ - '$id' => $deploymentId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'resourceId' => $site->getId(), - 'resourceInternalId' => $site->getSequence(), - 'resourceType' => 'sites', - 'buildCommands' => \implode(' && ', $commands), - 'buildOutput' => $site->getAttribute('outputDirectory', ''), - 'adapter' => $site->getAttribute('adapter', ''), - 'fallbackFile' => $site->getAttribute('fallbackFile', ''), - 'providerRepositoryName' => $repository, - 'providerRepositoryOwner' => $owner, - 'providerRepositoryUrl' => $repositoryUrl, - 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $branch, - 'providerCommitHash' => $commitDetails['commitHash'] ?? '', - 'providerCommitAuthorUrl' => $commitDetails['commitAuthorUrl'] ?? '', - 'providerCommitAuthor' => $commitDetails['commitAuthor'] ?? '', - 'providerCommitMessage' => mb_strimwidth($commitDetails['commitMessage'] ?? '', 0, 255, '...'), - 'providerCommitUrl' => $commitDetails['commitUrl'] ?? '', - 'type' => 'vcs', - 'activate' => $activate, - ])); - - $site = $site - ->setAttribute('latestDeploymentId', $deployment->getId()) - ->setAttribute('latestDeploymentInternalId', $deployment->getSequence()) - ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) - ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); - $dbForProject->updateDocument('sites', $site->getId(), $site); - - $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); - $domain = ID::unique() . "." . $sitesDomain; - - // TODO: @christyjacob remove once we migrate the rules in 1.7.x - $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - - Authorization::skip( - fn () => $dbForPlatform->createDocument('rules', new Document([ - '$id' => $ruleId, - 'projectId' => $project->getId(), - 'projectInternalId' => $project->getSequence(), - 'domain' => $domain, - 'type' => 'deployment', - 'trigger' => 'deployment', - 'deploymentId' => $deployment->isEmpty() ? '' : $deployment->getId(), - 'deploymentInternalId' => $deployment->isEmpty() ? '' : $deployment->getSequence(), - 'deploymentResourceType' => 'site', - 'deploymentResourceId' => $site->getId(), - 'deploymentResourceInternalId' => $site->getSequence(), - 'status' => 'verified', - 'certificateId' => '', - 'owner' => 'Appwrite', - 'region' => $project->getAttribute('region') - ])) - ); - - $queueForBuilds - ->setType(BUILD_TYPE_DEPLOYMENT) - ->setResource($site) - ->setDeployment($deployment) - ->setTemplate($template); - - $queueForEvents - ->setParam('siteId', $site->getId()) - ->setParam('deploymentId', $deployment->getId()); - - $response - ->setStatusCode(Response::STATUS_CODE_ACCEPTED) - ->dynamic($deployment, Response::MODEL_DEPLOYMENT); - } -} diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index 437356d4e2..6bd151f97e 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -4,7 +4,6 @@ namespace Appwrite\Platform\Modules\Sites\Services; use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Download\Get as DownloadDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Duplicate\Create as CreateDuplicateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment; @@ -61,7 +60,6 @@ class Http extends Service $this->addAction(DownloadDeployment::getName(), new DownloadDeployment()); $this->addAction(CreateDuplicateDeployment::getName(), new CreateDuplicateDeployment()); $this->addAction(UpdateDeploymentStatus::getName(), new UpdateDeploymentStatus()); - $this->addAction(CreateDirectDeployment::getName(), new CreateDirectDeployment()); // Logs $this->addAction(GetLog::getName(), new GetLog()); From fca27279660b7f13ca652a0f7ae9a417fe087cf6 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Sun, 14 Sep 2025 15:28:25 +0530 Subject: [PATCH 007/167] add validation for type --- .../Modules/Functions/Http/Deployments/Template/Create.php | 3 ++- .../Modules/Sites/Http/Deployments/Template/Create.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php index 885e23bfa1..6312c24d86 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php @@ -21,6 +21,7 @@ use Utopia\Platform\Scope\HTTP; use Utopia\Swoole\Request; use Utopia\Validator\Boolean; use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; use Utopia\VCS\Adapter\Git\GitHub; class Create extends Base @@ -66,7 +67,7 @@ class Create extends Base ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') ->param('rootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.') ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) - ->param('type', '', new Text(128, 0), 'Type for the reference provided. Can be commit, branch, or version', true) + ->param('type', '', new WhiteList(['commit', 'branch', 'tag']), 'Type for the reference provided. Can be commit, branch, or version', true) ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) ->inject('request') diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index 0799e0b51f..3721740e7f 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -23,6 +23,7 @@ use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; use Utopia\VCS\Adapter\Git\GitHub; class Create extends Base @@ -68,7 +69,7 @@ class Create extends Base ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') ->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) - ->param('type', '', new Text(128, 0), 'Type for the reference provided. Can be commit, branch, or version', true) + ->param('type', '', new WhiteList(['branch', 'commit', 'tag']), 'Type for the reference provided. Can be commit, branch, or version', true) ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) ->inject('request') From de8538b6222ec78e87dc9eaa81aa5d40b0b7e4cc Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Thu, 18 Sep 2025 12:27:24 +0530 Subject: [PATCH 008/167] use request filters for 1.8.0 to convert into and --- app/controllers/general.php | 4 +++ .../Http/Deployments/Template/Create.php | 21 ++++-------- .../Http/Deployments/Template/Create.php | 21 ++++-------- src/Appwrite/Utopia/Request/Filters/V21.php | 34 +++++++++++++++++++ 4 files changed, 50 insertions(+), 30 deletions(-) create mode 100644 src/Appwrite/Utopia/Request/Filters/V21.php diff --git a/app/controllers/general.php b/app/controllers/general.php index 8abca96742..c663091677 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -23,6 +23,7 @@ use Appwrite\Utopia\Request\Filters\V17 as RequestV17; use Appwrite\Utopia\Request\Filters\V18 as RequestV18; use Appwrite\Utopia\Request\Filters\V19 as RequestV19; use Appwrite\Utopia\Request\Filters\V20 as RequestV20; +use Appwrite\Utopia\Request\Filters\V21 as RequestV21; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Filters\V16 as ResponseV16; use Appwrite\Utopia\Response\Filters\V17 as ResponseV17; @@ -906,6 +907,9 @@ App::init() $dbForProject = $getProjectDB($project); $request->addFilter(new RequestV20($dbForProject, $route->getPathValues($request))); } + if (version_compare($requestFormat, '1.8.1', '<')) { + $request->addFilter(new RequestV21()); + } } $domain = $request->getHostname(); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php index 6312c24d86..5e0266a09e 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php @@ -66,9 +66,8 @@ class Create extends Base ->param('repository', '', new Text(128, 0), 'Repository name of the template.') ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') ->param('rootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.') - ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) - ->param('type', '', new WhiteList(['commit', 'branch', 'tag']), 'Type for the reference provided. Can be commit, branch, or version', true) - ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) + ->param('type', '', new WhiteList(['commit', 'branch', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag') + ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag') ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) ->inject('request') ->inject('response') @@ -86,7 +85,6 @@ class Create extends Base string $repository, string $owner, string $rootDirectory, - string $version, string $type, string $reference, bool $activate, @@ -105,22 +103,15 @@ class Create extends Base throw new Exception(Exception::FUNCTION_NOT_FOUND); } - if (empty($version) && empty($type) && empty($reference)) { - throw new Exception("Either version or type & reference must be provided"); - } - - $referenceType = !empty($version) ? GitHub::CLONE_TYPE_TAG : $type; - $referenceValue = !empty($version) ? $version : $reference; - - $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$referenceValue" : ""; + $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$reference" : ""; $repositoryUrl = "https://github.com/$owner/$repository"; $template = new Document([ 'repositoryName' => $repository, 'ownerName' => $owner, 'rootDirectory' => $rootDirectory, - 'referenceType' => $referenceType, - 'referenceValue' => $referenceValue, + 'referenceType' => $type, + 'referenceValue' => $reference, ]); if (!empty($function->getAttribute('providerRepositoryId'))) { @@ -166,7 +157,7 @@ class Create extends Base 'providerRepositoryOwner' => $owner, 'providerRepositoryUrl' => $repositoryUrl, 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $referenceValue : '', + 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $reference : '', 'type' => 'vcs', 'activate' => $activate, ])); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index 3721740e7f..d7196eb3d5 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -68,9 +68,8 @@ class Create extends Base ->param('repository', '', new Text(128, 0), 'Repository name of the template.') ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') ->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') - ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) - ->param('type', '', new WhiteList(['branch', 'commit', 'tag']), 'Type for the reference provided. Can be commit, branch, or version', true) - ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) + ->param('type', '', new WhiteList(['branch', 'commit', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag') + ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag') ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) ->inject('request') ->inject('response') @@ -88,7 +87,6 @@ class Create extends Base string $repository, string $owner, string $rootDirectory, - string $version, string $type, string $reference, bool $activate, @@ -107,22 +105,15 @@ class Create extends Base throw new Exception(Exception::SITE_NOT_FOUND); } - if (empty($version) && empty($type) && empty($reference)) { - throw new Exception("Either version or type & reference must be provided"); - } - - $referenceType = !empty($version) ? GitHub::CLONE_TYPE_TAG : $type; - $referenceValue = !empty($version) ? $version : $reference; - - $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$referenceValue" : ""; + $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$reference" : ""; $repositoryUrl = "https://github.com/$owner/$repository"; $template = new Document([ 'repositoryName' => $repository, 'ownerName' => $owner, 'rootDirectory' => $rootDirectory, - 'referenceType' => $referenceType, - 'referenceValue' => $referenceValue + 'referenceType' => $type, + 'referenceValue' => $reference ]); if (!empty($site->getAttribute('providerRepositoryId'))) { @@ -177,7 +168,7 @@ class Create extends Base 'providerRepositoryOwner' => $owner, 'providerRepositoryUrl' => $repositoryUrl, 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $referenceValue : '', + 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $reference : '', 'adapter' => $site->getAttribute('adapter', ''), 'fallbackFile' => $site->getAttribute('fallbackFile', ''), 'type' => 'vcs', diff --git a/src/Appwrite/Utopia/Request/Filters/V21.php b/src/Appwrite/Utopia/Request/Filters/V21.php new file mode 100644 index 0000000000..3ef0becf1d --- /dev/null +++ b/src/Appwrite/Utopia/Request/Filters/V21.php @@ -0,0 +1,34 @@ +convertVersionToTypeAndReference($content); + break; + } + return $content; + } + + /** + * Convert version parameter to type and reference for backwards compatibility + * with 1.8.0 template deployment endpoints + */ + protected function convertVersionToTypeAndReference(array $content): array + { + if (!empty($content['version'])) { + $content['type'] = 'tag'; + $content['reference'] = $content['version']; + unset($content['version']); + } + return $content; + } +} From 8e32fb05d1361778e64b583f468e2cd6d7de77f1 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Thu, 18 Sep 2025 12:28:08 +0530 Subject: [PATCH 009/167] specs --- .../specs/open-api3-latest-console.json | 40 +++++++++------ app/config/specs/open-api3-latest-server.json | 40 +++++++++------ app/config/specs/swagger2-latest-console.json | 50 +++++++++++-------- app/config/specs/swagger2-latest-server.json | 50 +++++++++++-------- 4 files changed, 104 insertions(+), 76 deletions(-) diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 96cec5c5a6..e052f542c9 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -12927,15 +12927,17 @@ "description": "Path to function code in the template repo.", "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", @@ -12951,7 +12953,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } @@ -30214,15 +30218,17 @@ "description": "Path to site code in the template repo.", "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", @@ -30238,7 +30244,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 3a1afab16b..b111f8e3e8 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -11709,15 +11709,17 @@ "description": "Path to function code in the template repo.", "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", @@ -11733,7 +11735,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } @@ -20921,15 +20925,17 @@ "description": "Path to site code in the template repo.", "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", @@ -20945,7 +20951,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 27604767b9..b359eaf310 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -12925,22 +12925,23 @@ "default": null, "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "default": "", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "default": "", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "default": null, + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", "description": "Reference value, can be a commit hash, branch name, or release tag", - "default": "", + "default": null, "x-example": "" }, "activate": { @@ -12953,7 +12954,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } @@ -30394,22 +30397,23 @@ "default": null, "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "default": "", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "default": "", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "default": null, + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", "description": "Reference value, can be a commit hash, branch name, or release tag", - "default": "", + "default": null, "x-example": "" }, "activate": { @@ -30422,7 +30426,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index a13c8324a4..b806a9e6c7 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -11732,22 +11732,23 @@ "default": null, "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "default": "", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "default": "", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "default": null, + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", "description": "Reference value, can be a commit hash, branch name, or release tag", - "default": "", + "default": null, "x-example": "" }, "activate": { @@ -11760,7 +11761,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } @@ -21144,22 +21147,23 @@ "default": null, "x-example": "" }, - "version": { - "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "default": "", - "x-example": "" - }, "type": { "type": "string", - "description": "Type for the reference provided. Can be commit, branch, or version", - "default": "", - "x-example": "" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "default": null, + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] }, "reference": { "type": "string", "description": "Reference value, can be a commit hash, branch name, or release tag", - "default": "", + "default": null, "x-example": "" }, "activate": { @@ -21172,7 +21176,9 @@ "required": [ "repository", "owner", - "rootDirectory" + "rootDirectory", + "type", + "reference" ] } } From 9fe3e94a669240e3a8669d9da28cdea51561358a Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Thu, 18 Sep 2025 13:12:46 +0530 Subject: [PATCH 010/167] e2e tests --- .../e2e/Services/Functions/FunctionsBase.php | 28 ++++ .../Functions/FunctionsCustomServerTest.php | 117 +++++++++++++- tests/e2e/Services/Sites/SitesBase.php | 29 ++++ .../Services/Sites/SitesCustomServerTest.php | 149 +++++++++++++++++- 4 files changed, 321 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index 27b67d851d..4eb31c08ac 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -268,6 +268,34 @@ trait FunctionsBase 'x-appwrite-project' => $this->getProject()['$id'], ])); + // Fetch latest commit from GitHub API if template has provider info + if ( + isset($template['body']['providerOwner']) && + isset($template['body']['providerRepositoryId']) + ) { + $owner = $template['body']['providerOwner']; + $repo = $template['body']['providerRepositoryId']; + + // GitHub API to get latest commit from main branch + $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'User-Agent: Appwrite', + 'Accept: application/vnd.github.v3+json' + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 200) { + $commitData = json_decode($response, true); + if (isset($commitData['sha'])) { + $template['body']['latestCommit'] = $commitData['sha']; + } + } + } + return $template; } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 0d63791151..8a774ed8bb 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -400,7 +400,8 @@ class FunctionsCustomServerTest extends Scope 'repository' => $starterTemplate['body']['providerRepositoryId'], 'owner' => $starterTemplate['body']['providerOwner'], 'rootDirectory' => $phpRuntime['providerRootDirectory'], - 'version' => $starterTemplate['body']['providerVersion'], + 'type' => 'tag', + 'reference' => $starterTemplate['body']['providerVersion'], ] ); @@ -502,6 +503,120 @@ class FunctionsCustomServerTest extends Scope $function = $this->cleanupFunction($functionId); } + public function testCreateFunctionAndDeploymentFromTemplateBranch() + { + $starterTemplate = $this->getTemplate('starter'); + $this->assertEquals(200, $starterTemplate['headers']['status-code']); + + $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + return $runtime['name'] === 'node-22'; + }))[0]; + + // If this fails, the template has variables, and this test needs to be updated + $this->assertEmpty($starterTemplate['body']['variables']); + + $function = $this->createFunction( + [ + 'functionId' => ID::unique(), + 'name' => $starterTemplate['body']['name'] . ' - Branch Test', + 'runtime' => 'node-22', + 'execute' => $starterTemplate['body']['permissions'], + 'entrypoint' => $phpRuntime['entrypoint'], + 'events' => $starterTemplate['body']['events'], + 'schedule' => $starterTemplate['body']['cron'], + 'timeout' => $starterTemplate['body']['timeout'], + 'commands' => $phpRuntime['commands'], + 'scopes' => $starterTemplate['body']['scopes'], + ] + ); + + $this->assertEquals(201, $function['headers']['status-code']); + $this->assertNotEmpty($function['body']['$id']); + + $functionId = $function['body']['$id'] ?? ''; + + // Deploy using branch + $deployment = $this->createTemplateDeployment( + $functionId, + [ + 'resourceId' => ID::unique(), + 'activate' => true, + 'repository' => $starterTemplate['body']['providerRepositoryId'], + 'owner' => $starterTemplate['body']['providerOwner'], + 'rootDirectory' => $phpRuntime['providerRootDirectory'], + 'type' => 'branch', + 'reference' => 'main', + ] + ); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + + $deployment = $this->getDeployment($functionId, $deployment['body']['$id']); + $this->assertEquals(200, $deployment['headers']['status-code']); + + $function = $this->cleanupFunction($functionId); + } + + public function testCreateFunctionAndDeploymentFromTemplateCommit() + { + $starterTemplate = $this->getTemplate('starter'); + $this->assertEquals(200, $starterTemplate['headers']['status-code']); + + // Ensure we have the latest commit + $this->assertArrayHasKey('latestCommit', $starterTemplate['body']); + $latestCommit = $starterTemplate['body']['latestCommit']; + + $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + return $runtime['name'] === 'node-22'; + }))[0]; + + // If this fails, the template has variables, and this test needs to be updated + $this->assertEmpty($starterTemplate['body']['variables']); + + $function = $this->createFunction( + [ + 'functionId' => ID::unique(), + 'name' => $starterTemplate['body']['name'] . ' - Commit Test', + 'runtime' => 'node-22', + 'execute' => $starterTemplate['body']['permissions'], + 'entrypoint' => $phpRuntime['entrypoint'], + 'events' => $starterTemplate['body']['events'], + 'schedule' => $starterTemplate['body']['cron'], + 'timeout' => $starterTemplate['body']['timeout'], + 'commands' => $phpRuntime['commands'], + 'scopes' => $starterTemplate['body']['scopes'], + ] + ); + + $this->assertEquals(201, $function['headers']['status-code']); + $this->assertNotEmpty($function['body']['$id']); + + $functionId = $function['body']['$id'] ?? ''; + + // Deploy using commit + $deployment = $this->createTemplateDeployment( + $functionId, + [ + 'resourceId' => ID::unique(), + 'activate' => true, + 'repository' => $starterTemplate['body']['providerRepositoryId'], + 'owner' => $starterTemplate['body']['providerOwner'], + 'rootDirectory' => $phpRuntime['providerRootDirectory'], + 'type' => 'commit', + 'reference' => $latestCommit, + ] + ); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + + $deployment = $this->getDeployment($functionId, $deployment['body']['$id']); + $this->assertEquals(200, $deployment['headers']['status-code']); + + $function = $this->cleanupFunction($functionId); + } + /** * @depends testUpdateFunction */ diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index 93c55b82b7..004032452b 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -329,6 +329,35 @@ trait SitesBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); + + // Fetch latest commit from GitHub API if template has provider info + if ( + isset($template['body']['providerOwner']) && + isset($template['body']['providerRepositoryId']) + ) { + $owner = $template['body']['providerOwner']; + $repo = $template['body']['providerRepositoryId']; + + // GitHub API to get latest commit from main branch + $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'User-Agent: Appwrite', + 'Accept: application/vnd.github.v3+json' + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 200) { + $commitData = json_decode($response, true); + if (isset($commitData['sha'])) { + $template['body']['latestCommit'] = $commitData['sha']; + } + } + } + return $template; } diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index c8301b9428..524e8a09f3 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1563,7 +1563,154 @@ class SitesCustomServerTest extends Scope 'repository' => $template['providerRepositoryId'], 'owner' => $template['providerOwner'], 'rootDirectory' => $template['frameworks'][0]['providerRootDirectory'], - 'version' => $template['providerVersion'], + 'type' => 'tag', + 'reference' => $template['providerVersion'], + 'activate' => true + ]); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + + $deployment = $this->getDeployment($siteId, $deployment['body']['$id']); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertEquals(0, $deployment['body']['sourceSize']); + $this->assertEquals(0, $deployment['body']['buildSize']); + $this->assertEquals(0, $deployment['body']['totalSize']); + + $this->assertEventually(function () use ($siteId) { + $site = $this->getSite($siteId); + $this->assertNotEmpty($site['body']['deploymentId']); + }, 50000, 500); + + $domain = $this->setupSiteDomain($siteId); + $proxyClient = new Client(); + $proxyClient->setEndpoint('http://' . $domain); + + $response = $proxyClient->call(Client::METHOD_GET, '/'); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertStringContainsString("Astro Blog", $response['body']); + $this->assertStringContainsString("Hello, Astronaut!", $response['body']); + + $response = $proxyClient->call(Client::METHOD_GET, '/about'); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertStringContainsString("Astro Blog", $response['body']); + $this->assertStringContainsString("About Me", $response['body']); + + $deployment = $this->getDeployment($siteId, $deployment['body']['$id']); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertGreaterThan(0, $deployment['body']['sourceSize']); + $this->assertGreaterThan(0, $deployment['body']['buildSize']); + $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; + $this->assertEquals($totalSize, $deployment['body']['totalSize']); + + $this->cleanupSite($siteId); + } + + public function testCreateSiteFromTemplateBranch() + { + $template = $this->getTemplate('playground-for-astro'); + $this->assertEquals(200, $template['headers']['status-code']); + + $template = $template['body']; + + $siteId = $this->setupSite([ + 'siteId' => ID::unique(), + 'name' => 'Astro Blog - Branch Test', + 'framework' => $template['frameworks'][0]['key'], + 'adapter' => $template['frameworks'][0]['adapter'], + 'buildRuntime' => $template['frameworks'][0]['buildRuntime'], + 'outputDirectory' => $template['frameworks'][0]['outputDirectory'], + 'buildCommand' => $template['frameworks'][0]['buildCommand'], + 'installCommand' => $template['frameworks'][0]['installCommand'], + 'fallbackFile' => $template['frameworks'][0]['fallbackFile'], + ]); + + $this->assertNotEmpty($siteId); + + // Deploy using branch + $deployment = $this->createTemplateDeployment($siteId, [ + 'repository' => $template['providerRepositoryId'], + 'owner' => $template['providerOwner'], + 'rootDirectory' => $template['frameworks'][0]['providerRootDirectory'], + 'type' => 'branch', + 'reference' => 'main', + 'activate' => true + ]); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + + $deployment = $this->getDeployment($siteId, $deployment['body']['$id']); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertEquals(0, $deployment['body']['sourceSize']); + $this->assertEquals(0, $deployment['body']['buildSize']); + $this->assertEquals(0, $deployment['body']['totalSize']); + + $this->assertEventually(function () use ($siteId) { + $site = $this->getSite($siteId); + $this->assertNotEmpty($site['body']['deploymentId']); + }, 50000, 500); + + $domain = $this->setupSiteDomain($siteId); + $proxyClient = new Client(); + $proxyClient->setEndpoint('http://' . $domain); + + $response = $proxyClient->call(Client::METHOD_GET, '/'); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertStringContainsString("Astro Blog", $response['body']); + $this->assertStringContainsString("Hello, Astronaut!", $response['body']); + + $response = $proxyClient->call(Client::METHOD_GET, '/about'); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertStringContainsString("Astro Blog", $response['body']); + $this->assertStringContainsString("About Me", $response['body']); + + $deployment = $this->getDeployment($siteId, $deployment['body']['$id']); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertGreaterThan(0, $deployment['body']['sourceSize']); + $this->assertGreaterThan(0, $deployment['body']['buildSize']); + $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; + $this->assertEquals($totalSize, $deployment['body']['totalSize']); + + $this->cleanupSite($siteId); + } + + public function testCreateSiteFromTemplateCommit() + { + $template = $this->getTemplate('playground-for-astro'); + $this->assertEquals(200, $template['headers']['status-code']); + + // Ensure we have the latest commit + $this->assertArrayHasKey('latestCommit', $template['body']); + $latestCommit = $template['body']['latestCommit']; + + $template = $template['body']; + + $siteId = $this->setupSite([ + 'siteId' => ID::unique(), + 'name' => 'Astro Blog - Commit Test', + 'framework' => $template['frameworks'][0]['key'], + 'adapter' => $template['frameworks'][0]['adapter'], + 'buildRuntime' => $template['frameworks'][0]['buildRuntime'], + 'outputDirectory' => $template['frameworks'][0]['outputDirectory'], + 'buildCommand' => $template['frameworks'][0]['buildCommand'], + 'installCommand' => $template['frameworks'][0]['installCommand'], + 'fallbackFile' => $template['frameworks'][0]['fallbackFile'], + ]); + + $this->assertNotEmpty($siteId); + + // Deploy using commit + $deployment = $this->createTemplateDeployment($siteId, [ + 'repository' => $template['providerRepositoryId'], + 'owner' => $template['providerOwner'], + 'rootDirectory' => $template['frameworks'][0]['providerRootDirectory'], + 'type' => 'commit', + 'reference' => $latestCommit, 'activate' => true ]); From 2a145bc284d1edff27014187b316493af85448b6 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 19 Sep 2025 18:18:44 +0530 Subject: [PATCH 011/167] address reviews regarding tests --- .../e2e/Services/Functions/FunctionsBase.php | 41 ++++----- .../Functions/FunctionsCustomServerTest.php | 87 ++++++++++++------- tests/e2e/Services/Sites/SitesBase.php | 41 ++++----- .../Services/Sites/SitesCustomServerTest.php | 9 +- 4 files changed, 97 insertions(+), 81 deletions(-) diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index 4eb31c08ac..7403b23a73 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -268,35 +268,30 @@ trait FunctionsBase 'x-appwrite-project' => $this->getProject()['$id'], ])); - // Fetch latest commit from GitHub API if template has provider info - if ( - isset($template['body']['providerOwner']) && - isset($template['body']['providerRepositoryId']) - ) { - $owner = $template['body']['providerOwner']; - $repo = $template['body']['providerRepositoryId']; + return $template; + } - // GitHub API to get latest commit from main branch - $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'User-Agent: Appwrite', - 'Accept: application/vnd.github.v3+json' - ]); + protected function helperGetLatestCommit(string $owner, string $repository): ?string + { + $ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'User-Agent: Appwrite', + 'Accept: application/vnd.github.v3+json' + ]); - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); - if ($httpCode === 200) { - $commitData = json_decode($response, true); - if (isset($commitData['sha'])) { - $template['body']['latestCommit'] = $commitData['sha']; - } + if ($httpCode === 200) { + $commitData = json_decode($response, true); + if (isset($commitData['sha'])) { + return $commitData['sha']; } } - return $template; + return null; } protected function createExecution(string $functionId, mixed $params = []): mixed diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 8a774ed8bb..5672bd9817 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -361,7 +361,7 @@ class FunctionsCustomServerTest extends Scope $starterTemplate = $this->getTemplate('starter'); $this->assertEquals(200, $starterTemplate['headers']['status-code']); - $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + $runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { return $runtime['name'] === 'node-22'; }))[0]; @@ -374,15 +374,15 @@ class FunctionsCustomServerTest extends Scope 'name' => $starterTemplate['body']['name'], 'runtime' => 'node-22', 'execute' => $starterTemplate['body']['permissions'], - 'entrypoint' => $phpRuntime['entrypoint'], + 'entrypoint' => $runtime['entrypoint'], 'events' => $starterTemplate['body']['events'], 'schedule' => $starterTemplate['body']['cron'], 'timeout' => $starterTemplate['body']['timeout'], - 'commands' => $phpRuntime['commands'], + 'commands' => $runtime['commands'], 'scopes' => $starterTemplate['body']['scopes'], 'templateRepository' => $starterTemplate['body']['providerRepositoryId'], 'templateOwner' => $starterTemplate['body']['providerOwner'], - 'templateRootDirectory' => $phpRuntime['providerRootDirectory'], + 'templateRootDirectory' => $runtime['providerRootDirectory'], 'templateVersion' => $starterTemplate['body']['providerVersion'], ] ); @@ -399,7 +399,7 @@ class FunctionsCustomServerTest extends Scope 'activate' => true, 'repository' => $starterTemplate['body']['providerRepositoryId'], 'owner' => $starterTemplate['body']['providerOwner'], - 'rootDirectory' => $phpRuntime['providerRootDirectory'], + 'rootDirectory' => $runtime['providerRootDirectory'], 'type' => 'tag', 'reference' => $starterTemplate['body']['providerVersion'], ] @@ -408,11 +408,20 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); $this->assertNotEmpty($deployment['body']['$id']); - $deployment = $this->getDeployment($functionId, $deployment['body']['$id']); + // Wait for deployment to be ready + $deploymentId = $deployment['body']['$id']; + $this->assertEventually(function () use ($functionId, $deploymentId) { + $deployment = $this->getDeployment($functionId, $deploymentId); + $this->assertEquals('ready', $deployment['body']['status']); + }, 50000, 500); + + // Verify deployment sizes + $deployment = $this->getDeployment($functionId, $deploymentId); $this->assertEquals(200, $deployment['headers']['status-code']); - $this->assertEquals(0, $deployment['body']['sourceSize']); - $this->assertEquals(0, $deployment['body']['buildSize']); - $this->assertEquals(0, $deployment['body']['totalSize']); + $this->assertGreaterThan(0, $deployment['body']['sourceSize']); + $this->assertGreaterThan(0, $deployment['body']['buildSize']); + $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; + $this->assertEquals($totalSize, $deployment['body']['totalSize']); $deployments = $this->listDeployments($functionId); @@ -422,16 +431,7 @@ class FunctionsCustomServerTest extends Scope $lastDeployment = $deployments['body']['deployments'][0]; $this->assertNotEmpty($lastDeployment['$id']); - $this->assertEquals(0, $lastDeployment['sourceSize']); - - $deploymentId = $lastDeployment['$id']; - - $this->assertEventually(function () use ($functionId, $deploymentId) { - $deployment = $this->getDeployment($functionId, $deploymentId); - - $this->assertEquals(200, $deployment['headers']['status-code']); - $this->assertEquals('ready', $deployment['body']['status']); - }, 50000, 1000); + $this->assertGreaterThan(0, $lastDeployment['sourceSize']); $function = $this->getFunction($functionId); @@ -508,7 +508,7 @@ class FunctionsCustomServerTest extends Scope $starterTemplate = $this->getTemplate('starter'); $this->assertEquals(200, $starterTemplate['headers']['status-code']); - $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + $runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { return $runtime['name'] === 'node-22'; }))[0]; @@ -521,11 +521,11 @@ class FunctionsCustomServerTest extends Scope 'name' => $starterTemplate['body']['name'] . ' - Branch Test', 'runtime' => 'node-22', 'execute' => $starterTemplate['body']['permissions'], - 'entrypoint' => $phpRuntime['entrypoint'], + 'entrypoint' => $runtime['entrypoint'], 'events' => $starterTemplate['body']['events'], 'schedule' => $starterTemplate['body']['cron'], 'timeout' => $starterTemplate['body']['timeout'], - 'commands' => $phpRuntime['commands'], + 'commands' => $runtime['commands'], 'scopes' => $starterTemplate['body']['scopes'], ] ); @@ -543,7 +543,7 @@ class FunctionsCustomServerTest extends Scope 'activate' => true, 'repository' => $starterTemplate['body']['providerRepositoryId'], 'owner' => $starterTemplate['body']['providerOwner'], - 'rootDirectory' => $phpRuntime['providerRootDirectory'], + 'rootDirectory' => $runtime['providerRootDirectory'], 'type' => 'branch', 'reference' => 'main', ] @@ -552,8 +552,18 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); $this->assertNotEmpty($deployment['body']['$id']); - $deployment = $this->getDeployment($functionId, $deployment['body']['$id']); + $deploymentId = $deployment['body']['$id']; + $this->assertEventually(function () use ($functionId, $deploymentId) { + $deployment = $this->getDeployment($functionId, $deploymentId); + $this->assertEquals('ready', $deployment['body']['status']); + }, 50000, 500); + + $deployment = $this->getDeployment($functionId, $deploymentId); $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertGreaterThan(0, $deployment['body']['sourceSize']); + $this->assertGreaterThan(0, $deployment['body']['buildSize']); + $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; + $this->assertEquals($totalSize, $deployment['body']['totalSize']); $function = $this->cleanupFunction($functionId); } @@ -563,11 +573,14 @@ class FunctionsCustomServerTest extends Scope $starterTemplate = $this->getTemplate('starter'); $this->assertEquals(200, $starterTemplate['headers']['status-code']); - // Ensure we have the latest commit - $this->assertArrayHasKey('latestCommit', $starterTemplate['body']); - $latestCommit = $starterTemplate['body']['latestCommit']; + // Get latest commit using helper function + $latestCommit = $this->helperGetLatestCommit( + $starterTemplate['body']['providerOwner'], + $starterTemplate['body']['providerRepositoryId'] + ); + $this->assertNotNull($latestCommit); - $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + $runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { return $runtime['name'] === 'node-22'; }))[0]; @@ -580,11 +593,11 @@ class FunctionsCustomServerTest extends Scope 'name' => $starterTemplate['body']['name'] . ' - Commit Test', 'runtime' => 'node-22', 'execute' => $starterTemplate['body']['permissions'], - 'entrypoint' => $phpRuntime['entrypoint'], + 'entrypoint' => $runtime['entrypoint'], 'events' => $starterTemplate['body']['events'], 'schedule' => $starterTemplate['body']['cron'], 'timeout' => $starterTemplate['body']['timeout'], - 'commands' => $phpRuntime['commands'], + 'commands' => $runtime['commands'], 'scopes' => $starterTemplate['body']['scopes'], ] ); @@ -602,7 +615,7 @@ class FunctionsCustomServerTest extends Scope 'activate' => true, 'repository' => $starterTemplate['body']['providerRepositoryId'], 'owner' => $starterTemplate['body']['providerOwner'], - 'rootDirectory' => $phpRuntime['providerRootDirectory'], + 'rootDirectory' => $runtime['providerRootDirectory'], 'type' => 'commit', 'reference' => $latestCommit, ] @@ -611,8 +624,18 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); $this->assertNotEmpty($deployment['body']['$id']); - $deployment = $this->getDeployment($functionId, $deployment['body']['$id']); + $deploymentId = $deployment['body']['$id']; + $this->assertEventually(function () use ($functionId, $deploymentId) { + $deployment = $this->getDeployment($functionId, $deploymentId); + $this->assertEquals('ready', $deployment['body']['status']); + }, 50000, 500); + + $deployment = $this->getDeployment($functionId, $deploymentId); $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertGreaterThan(0, $deployment['body']['sourceSize']); + $this->assertGreaterThan(0, $deployment['body']['buildSize']); + $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; + $this->assertEquals($totalSize, $deployment['body']['totalSize']); $function = $this->cleanupFunction($functionId); } diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index 004032452b..7eb5d9699c 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -330,35 +330,30 @@ trait SitesBase 'x-appwrite-project' => $this->getProject()['$id'], ]); - // Fetch latest commit from GitHub API if template has provider info - if ( - isset($template['body']['providerOwner']) && - isset($template['body']['providerRepositoryId']) - ) { - $owner = $template['body']['providerOwner']; - $repo = $template['body']['providerRepositoryId']; + return $template; + } - // GitHub API to get latest commit from main branch - $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'User-Agent: Appwrite', - 'Accept: application/vnd.github.v3+json' - ]); + protected function helperGetLatestCommit(string $owner, string $repository): ?string + { + $ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'User-Agent: Appwrite', + 'Accept: application/vnd.github.v3+json' + ]); - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); - if ($httpCode === 200) { - $commitData = json_decode($response, true); - if (isset($commitData['sha'])) { - $template['body']['latestCommit'] = $commitData['sha']; - } + if ($httpCode === 200) { + $commitData = json_decode($response, true); + if (isset($commitData['sha'])) { + return $commitData['sha']; } } - return $template; + return null; } protected function deleteSite(string $siteId): mixed diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 524e8a09f3..f7015ccb48 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1684,9 +1684,12 @@ class SitesCustomServerTest extends Scope $template = $this->getTemplate('playground-for-astro'); $this->assertEquals(200, $template['headers']['status-code']); - // Ensure we have the latest commit - $this->assertArrayHasKey('latestCommit', $template['body']); - $latestCommit = $template['body']['latestCommit']; + // Get latest commit using helper function + $latestCommit = $this->helperGetLatestCommit( + $template['body']['providerOwner'], + $template['body']['providerRepositoryId'] + ); + $this->assertNotNull($latestCommit); $template = $template['body']; From 1a19e01d69d563aff5942ea836cfdb8b484875ee Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 19 Sep 2025 18:30:42 +0530 Subject: [PATCH 012/167] attempt to fix tests --- tests/e2e/General/UsageTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 8f5477331a..dc49d27aea 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -28,6 +28,7 @@ class UsageTest extends Scope FunctionsBase::createVariable insteadof SitesBase; FunctionsBase::getVariable insteadof SitesBase; FunctionsBase::listVariables insteadof SitesBase; + FunctionsBase::helperGetLatestCommit insteadof SitesBase; FunctionsBase::updateVariable insteadof SitesBase; FunctionsBase::deleteVariable insteadof SitesBase; FunctionsBase::getDeployment insteadof SitesBase; From 7d4486b9e691789bed9a68e62df2f455e18d57ce Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 19 Sep 2025 18:42:25 +0530 Subject: [PATCH 013/167] more fixes to tests --- tests/e2e/Services/Functions/FunctionsCustomServerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 5672bd9817..a3f8768676 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -500,7 +500,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals($deployment['body']['$id'], $function['body']['deploymentId']); $this->assertEquals($deployment['body']['$createdAt'], $function['body']['deploymentCreatedAt']); - $function = $this->cleanupFunction($functionId); + $this->cleanupFunction($functionId); } public function testCreateFunctionAndDeploymentFromTemplateBranch() @@ -565,7 +565,7 @@ class FunctionsCustomServerTest extends Scope $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; $this->assertEquals($totalSize, $deployment['body']['totalSize']); - $function = $this->cleanupFunction($functionId); + $this->cleanupFunction($functionId); } public function testCreateFunctionAndDeploymentFromTemplateCommit() @@ -637,7 +637,7 @@ class FunctionsCustomServerTest extends Scope $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; $this->assertEquals($totalSize, $deployment['body']['totalSize']); - $function = $this->cleanupFunction($functionId); + $this->cleanupFunction($functionId); } /** From 5963b2baf799d99c5bcb7610595b5ed70fc4ef48 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Tue, 23 Sep 2025 18:00:14 +0530 Subject: [PATCH 014/167] change request filter to versions below 1.9.0 --- app/controllers/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index c663091677..f0294e9274 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -907,7 +907,7 @@ App::init() $dbForProject = $getProjectDB($project); $request->addFilter(new RequestV20($dbForProject, $route->getPathValues($request))); } - if (version_compare($requestFormat, '1.8.1', '<')) { + if (version_compare($requestFormat, '1.9.0', '<')) { $request->addFilter(new RequestV21()); } } From 33f88fa5e0ad2a9686990df2987ef73a0ae062fa Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 22 Oct 2025 16:35:48 +0300 Subject: [PATCH 015/167] Refactor authorization handling across multiple modules to use the new getAuthorization() method. Update CHANGES.md to reflect the change in usage worker authorization. Adjust composer.json to specify the correct version for utopia-php/database. Update plugin-api-version in composer.lock. --- CHANGES.md | 2 +- app/cli.php | 29 ++-- app/controllers/api/account.php | 80 +++++----- app/controllers/api/avatars.php | 12 +- app/controllers/api/graphql.php | 5 +- app/controllers/api/messaging.php | 41 +++-- app/controllers/api/migrations.php | 8 +- app/controllers/api/project.php | 6 +- app/controllers/api/storage.php | 151 ++++++++---------- app/controllers/api/teams.php | 42 ++--- app/controllers/api/users.php | 2 +- app/controllers/api/vcs.php | 38 ++--- app/controllers/general.php | 37 ++--- app/controllers/shared/api.php | 45 +++--- app/controllers/shared/api/auth.php | 7 +- app/http.php | 21 ++- app/init/database/filters.php | 14 +- app/init/resources.php | 55 ++++--- app/realtime.php | 22 +-- app/worker.php | 39 +++-- composer.json | 2 +- composer.lock | 96 ++++++++--- src/Appwrite/Auth/Auth.php | 4 +- src/Appwrite/Databases/TransactionState.php | 4 +- src/Appwrite/Migration/Migration.php | 5 +- .../Platform/Modules/Compute/Base.php | 6 +- .../Modules/Console/Http/Resources/Get.php | 2 +- .../Collections/Attributes/Action.php | 6 +- .../Collections/Attributes/Delete.php | 2 +- .../Databases/Collections/Attributes/Get.php | 2 +- .../Attributes/Relationship/Create.php | 2 +- .../Collections/Attributes/XList.php | 2 +- .../Http/Databases/Collections/Create.php | 2 +- .../Http/Databases/Collections/Delete.php | 2 +- .../Collections/Documents/Action.php | 2 +- .../Documents/Attribute/Decrement.php | 10 +- .../Documents/Attribute/Increment.php | 10 +- .../Collections/Documents/Create.php | 34 ++-- .../Collections/Documents/Delete.php | 12 +- .../Databases/Collections/Documents/Get.php | 8 +- .../Collections/Documents/Logs/XList.php | 2 +- .../Collections/Documents/Update.php | 20 +-- .../Collections/Documents/Upsert.php | 20 +-- .../Databases/Collections/Documents/XList.php | 10 +- .../Http/Databases/Collections/Get.php | 2 +- .../Databases/Collections/Indexes/Create.php | 2 +- .../Databases/Collections/Indexes/Delete.php | 2 +- .../Databases/Collections/Indexes/Get.php | 2 +- .../Databases/Collections/Indexes/XList.php | 4 +- .../Http/Databases/Collections/Logs/XList.php | 2 +- .../Http/Databases/Collections/Update.php | 2 +- .../Http/Databases/Collections/Usage/Get.php | 2 +- .../Http/Databases/Collections/XList.php | 2 +- .../Http/Databases/Transactions/Create.php | 2 +- .../Transactions/Operations/Create.php | 24 +-- .../Http/Databases/Transactions/Update.php | 30 ++-- .../Databases/Http/Databases/Usage/Get.php | 2 +- .../Databases/Http/Databases/Usage/XList.php | 2 +- .../Functions/Http/Executions/Create.php | 22 ++- .../Functions/Http/Executions/Delete.php | 2 +- .../Modules/Functions/Http/Executions/Get.php | 6 +- .../Functions/Http/Executions/XList.php | 6 +- .../Functions/Http/Functions/Create.php | 4 +- .../Functions/Http/Functions/Delete.php | 2 +- .../Http/Functions/Deployment/Update.php | 6 +- .../Functions/Http/Functions/Update.php | 2 +- .../Modules/Functions/Http/Usage/Get.php | 2 +- .../Modules/Functions/Http/Usage/XList.php | 2 +- .../Functions/Http/Variables/Create.php | 2 +- .../Functions/Http/Variables/Delete.php | 2 +- .../Functions/Http/Variables/Update.php | 2 +- .../Modules/Functions/Workers/Builds.php | 10 +- .../Modules/Sites/Http/Deployments/Create.php | 4 +- .../Http/Deployments/Duplicate/Create.php | 2 +- .../Http/Deployments/Template/Create.php | 2 +- .../Sites/Http/Sites/Deployment/Update.php | 4 +- .../Platform/Modules/Sites/Http/Usage/Get.php | 2 +- .../Modules/Sites/Http/Usage/XList.php | 2 +- .../Http/Tokens/Buckets/Files/Action.php | 16 +- .../Http/Tokens/Buckets/Files/Create.php | 9 +- src/Appwrite/Platform/Tasks/Migrate.php | 2 +- src/Appwrite/Platform/Tasks/ScheduleBase.php | 2 +- .../Platform/Tasks/StatsResources.php | 6 +- src/Appwrite/Platform/Workers/Deletes.php | 4 +- src/Appwrite/Utopia/Request.php | 9 +- src/Appwrite/Utopia/Request/Filters/V20.php | 4 +- src/Appwrite/Utopia/Response.php | 9 +- .../DatabasesPermissionsGuestTest.php | 22 ++- .../DatabasesPermissionsGuestTest.php | 23 ++- tests/unit/Auth/AuthTest.php | 31 ++-- .../unit/Messaging/MessagingChannelsTest.php | 15 +- 91 files changed, 688 insertions(+), 551 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index bc903e4b31..1ca2410aec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1155,7 +1155,7 @@ * Bump console to version 3.2.7 [#7148](https://github.com/appwrite/appwrite/pull/7148) * Chore update database to 0.45.2 [#7138](https://github.com/appwrite/appwrite/pull/7138) * Implement queue thresholds for the health API [#7123](https://github.com/appwrite/appwrite/pull/7123) -* Add Authorization::skip to the usage worker [#7124](https://github.com/appwrite/appwrite/pull/7124) +* Add Authorization->skip to the usage worker [#7124](https://github.com/appwrite/appwrite/pull/7124) ## Bug fixes * fix: use queueForDeletes in git installation delete endpoint [#7140](https://github.com/appwrite/appwrite/pull/7140) diff --git a/app/cli.php b/app/cli.php index 71b6464cb9..08726c2d4d 100644 --- a/app/cli.php +++ b/app/cli.php @@ -40,8 +40,6 @@ Config::setParam('runtimes', (new Runtimes('v5'))->getAll(supported: false)); // require controllers after overwriting runtimes require_once __DIR__ . '/controllers/general.php'; -Authorization::disable(); - CLI::setResource('register', fn () => $register); CLI::setResource('cache', function ($pools) { @@ -59,7 +57,12 @@ CLI::setResource('pools', function (Registry $register) { return $register->get('pools'); }, ['register']); -CLI::setResource('dbForPlatform', function ($pools, $cache) { +CLI::setResource('authorization', function () { + $authorization = new Authorization(); + return $authorization; +}, []); + +CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { $sleep = 3; $maxAttempts = 5; $attempts = 0; @@ -73,6 +76,7 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) { $dbForPlatform = new Database($adapter, $cache); $dbForPlatform + ->setAuthorization($authorization) ->setNamespace('_console') ->setMetadata('host', \gethostname()) ->setMetadata('project', 'console'); @@ -97,7 +101,7 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) { } return $dbForPlatform; -}, ['pools', 'cache']); +}, ['pools', 'cache', 'authorization']); CLI::setResource('console', function () { return new Document(Config::getParam('console')); @@ -108,10 +112,10 @@ CLI::setResource( fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false ); -CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) { +CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, $authorization) { $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools - return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) { + return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -129,11 +133,13 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform if (\in_array($dsn->getHost(), $sharedTables)) { $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database + ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -149,11 +155,13 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform if (\in_array($dsn->getHost(), $sharedTables)) { $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database + ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -165,12 +173,12 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform return $database; }; -}, ['pools', 'dbForPlatform', 'cache']); +}, ['pools', 'dbForPlatform', 'cache', 'authorization']); -CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) { +CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { $database = null; - return function (?Document $project = null) use ($pools, $cache, $database) { + return function (?Document $project = null) use ($pools, $cache, $database, $authorization) { if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') { $database->setTenant((int)$project->getSequence()); return $database; @@ -180,6 +188,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database = new Database($adapter, $cache); $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK) @@ -192,7 +201,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) { return $database; }; -}, ['pools', 'cache']); +}, ['pools', 'cache', 'authorization']); CLI::setResource('publisher', function (Group $pools) { return new BrokerPool(publisher: $pools->get('publisher')); }, ['pools']); diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 5563fc6a59..aeeff76dff 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -173,7 +173,7 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc $createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails) { /** @var Utopia\Database\Document $user */ - $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + $userFromRequest = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_INVALID_TOKEN); @@ -219,7 +219,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res $detector->getDevice() )); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session ->setAttribute('$permissions', [ @@ -228,7 +228,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res Permission::delete(Role::user($user->getId())), ])); - Authorization::skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); $dbForProject->purgeCachedDocument('users', $user->getId()); // Magic URL + Email OTP @@ -403,9 +403,9 @@ App::post('/v1/account') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -431,9 +431,9 @@ App::post('/v1/account') throw new Exception(Exception::USER_ALREADY_EXISTS); } - Authorization::unsetRole(Role::guests()->toString()); - Authorization::setRole(Role::user($user->getId())->toString()); - Authorization::setRole(Role::users()->toString()); + $dbForProject->getAuthorization()->removeRole(Role::guests()->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::users()->toString()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -937,7 +937,7 @@ App::post('/v1/account/sessions/email') $detector->getDevice() )); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); // Re-hash if not using recommended algo if ($user->getAttribute('hash') !== Auth::DEFAULT_ALGO) { @@ -1074,7 +1074,7 @@ App::post('/v1/account/sessions/anonymous') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + $dbForProject->getAuthorization()-> skip(fn () => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; @@ -1100,7 +1100,7 @@ App::post('/v1/account/sessions/anonymous') $detector->getDevice() )); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [ Permission::read(Role::user($user->getId())), @@ -1606,7 +1606,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $userDoc = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + $userDoc = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), @@ -1625,8 +1625,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } } - Authorization::setRole(Role::user($user->getId())->toString()); - Authorization::setRole(Role::users()->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::users()->toString()); if (false === $user->getAttribute('status')) { // Account is blocked $failureRedirect(Exception::USER_BLOCKED); // User is in status blocked @@ -1685,7 +1685,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->updateDocument('users', $user->getId(), $user); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $state['success'] = URLParser::parse($state['success']); $query = URLParser::parseQuery($state['success']['query']); @@ -1707,7 +1707,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -1996,7 +1996,7 @@ App::post('/v1/account/tokens/magic-url') ]); $user->removeAttribute('$sequence'); - Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); } $tokenSecret = Auth::tokenGenerator(Auth::TOKEN_LENGTH_MAGIC_URL); @@ -2013,7 +2013,7 @@ App::post('/v1/account/tokens/magic-url') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -2244,9 +2244,9 @@ App::post('/v1/account/tokens/email') ]); $user->removeAttribute('$sequence'); - $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2284,7 +2284,7 @@ App::post('/v1/account/tokens/email') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -2591,9 +2591,9 @@ App::post('/v1/account/tokens/phone') ]); $user->removeAttribute('$sequence'); - Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2639,7 +2639,7 @@ App::post('/v1/account/tokens/phone') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -3063,7 +3063,7 @@ App::patch('/v1/account/email') ->setAttribute('passwordUpdate', DateTime::now()); } - $target = Authorization::skip(fn () => $dbForProject->findOne('targets', [ + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$email]), ])); @@ -3079,7 +3079,7 @@ App::patch('/v1/account/email') $oldTarget = $user->find('identifier', $oldEmail, 'targets'); if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { - Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); } $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Duplicate) { @@ -3134,7 +3134,7 @@ App::patch('/v1/account/phone') $hooks->trigger('passwordValidator', [$dbForProject, $project, $password, &$user, false]); - $target = Authorization::skip(fn () => $dbForProject->findOne('targets', [ + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), ])); @@ -3165,7 +3165,7 @@ App::patch('/v1/account/phone') $oldTarget = $user->find('identifier', $oldPhone, 'targets'); if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { - Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); } $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Duplicate $th) { @@ -3335,7 +3335,7 @@ App::post('/v1/account/recovery') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($profile->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); $recovery = $dbForProject->createDocument('tokens', $recovery ->setAttribute('$permissions', [ @@ -3491,7 +3491,7 @@ App::put('/v1/account/recovery') throw new Exception(Exception::USER_INVALID_TOKEN); } - Authorization::setRole(Role::user($profile->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); @@ -3618,7 +3618,7 @@ App::post('/v1/account/verifications/email') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $verification = $dbForProject->createDocument('tokens', $verification ->setAttribute('$permissions', [ @@ -3803,7 +3803,7 @@ App::put('/v1/account/verifications/email') ->inject('queueForEvents') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + $profile = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -3816,7 +3816,7 @@ App::put('/v1/account/verifications/email') throw new Exception(Exception::USER_INVALID_TOKEN); } - Authorization::setRole(Role::user($profile->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); $profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('emailVerification', true)); @@ -3914,7 +3914,7 @@ App::post('/v1/account/verifications/phone') 'ip' => $request->getIP(), ]); - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $verification = $dbForProject->createDocument('tokens', $verification ->setAttribute('$permissions', [ @@ -4021,7 +4021,7 @@ App::put('/v1/account/verifications/phone') ->inject('queueForEvents') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + $profile = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -4033,7 +4033,7 @@ App::put('/v1/account/verifications/phone') throw new Exception(Exception::USER_INVALID_TOKEN); } - Authorization::setRole(Role::user($profile->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); $profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('phoneVerification', true)); @@ -5024,9 +5024,9 @@ App::post('/v1/account/targets/push') ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; - $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $provider = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('providers', $providerId)); - $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if (!$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); @@ -5103,7 +5103,7 @@ App::put('/v1/account/targets/:targetId/push') ->inject('dbForProject') ->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { - $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); @@ -5167,7 +5167,7 @@ App::delete('/v1/account/targets/:targetId/push') ->inject('response') ->inject('dbForProject') ->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject) { - $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 90364d997e..64f13c1981 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -69,7 +69,7 @@ $avatarCallback = function (string $type, string $code, int $width, int $height, $getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, ?Logger $logger) { try { - $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); $sessions = $user->getAttribute('sessions', []); @@ -120,7 +120,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro ->setAttribute('providerRefreshToken', $refreshToken) ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); - Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Throwable $err) { @@ -128,7 +128,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro do { $previousAccessToken = $gitHubSession->getAttribute('providerAccessToken'); - $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); $sessions = $user->getAttribute('sessions', []); $gitHubSession = new Document(); @@ -658,7 +658,7 @@ App::get('/v1/cards/cloud') ->inject('employees') ->inject('logger') ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { - $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -865,7 +865,7 @@ App::get('/v1/cards/cloud-back') ->inject('employees') ->inject('logger') ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { - $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -943,7 +943,7 @@ App::get('/v1/cards/cloud-og') ->inject('employees') ->inject('logger') ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { - $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); diff --git a/app/controllers/api/graphql.php b/app/controllers/api/graphql.php index 482b38d698..d0480225da 100644 --- a/app/controllers/api/graphql.php +++ b/app/controllers/api/graphql.php @@ -28,11 +28,12 @@ use Utopia\Validator\Text; App::init() ->groups(['graphql']) ->inject('project') - ->action(function (Document $project) { + ->inject('authorization') + ->action(function (Document $project, Authorization $authorization) { if ( array_key_exists('graphql', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['graphql'] - && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) + && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index dbc384f3c4..6029f7642e 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -35,7 +35,7 @@ use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; @@ -1013,7 +1013,7 @@ App::get('/v1/messaging/providers') } $providerId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('providers', $providerId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); @@ -2320,7 +2320,7 @@ App::get('/v1/messaging/topics') } $topicId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Topic '{$topicId}' for the 'cursor' value not found."); @@ -2599,25 +2599,22 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Response $response) { $subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId; - $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - - $validator = new Authorization('subscribe'); - - if (!$validator->isValid($topic->getAttribute('subscribe'))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); + if (!$dbForProject->getAuthorization()->isValid(new Input('subscribe', $topic->getAttribute('subscribe')))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } - $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber = new Document([ '$id' => $subscriberId, @@ -2650,7 +2647,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), }; - Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute( + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->increaseDocumentAttribute( 'topics', $topicId, $totalAttribute, @@ -2706,7 +2703,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $queries[] = Query::search('search', $search); } - $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -2729,7 +2726,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') } $subscriberId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Subscriber '{$subscriberId}' for the 'cursor' value not found."); @@ -2745,8 +2742,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { return function () use ($subscriber, $dbForProject) { - $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); return $subscriber ->setAttribute('target', $target) @@ -2882,7 +2879,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') ->inject('dbForProject') ->inject('response') ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) { - $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -2894,8 +2891,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } - $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber ->setAttribute('target', $target) @@ -2933,7 +2930,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') ->inject('dbForProject') ->inject('response') ->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Response $response) { - $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -2956,7 +2953,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), }; - Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute( + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->decreaseDocumentAttribute( 'topics', $topicId, $totalAttribute, @@ -3539,7 +3536,7 @@ App::get('/v1/messaging/messages') } $messageId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('messages', $messageId)); + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('messages', $messageId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Message '{$messageId}' for the 'cursor' value not found."); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 4a968e63f2..4f88adf616 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -339,12 +339,12 @@ App::post('/v1/migrations/csv') ->inject('queueForEvents') ->inject('queueForMigrations') ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Device $deviceForFiles, Device $deviceForImports, Event $queueForEvents, Migration $queueForMigrations) { - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForPlatform->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForPlatform->getAuthorization()->getRoles()); if ($internalFile && !$isPrivilegedUser) { throw new Exception(Exception::USER_UNAUTHORIZED); } - $bucket = Authorization::skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { + $bucket = $dbForPlatform->getAuthorization()->skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { if ($internalFile) { return $dbForPlatform->getDocument('buckets', 'default'); } @@ -355,7 +355,7 @@ App::post('/v1/migrations/csv') throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = Authorization::skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForPlatform->getAuthorization()->skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 390e88637a..554d2defec 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -101,7 +101,7 @@ App::get('/v1/project/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - Authorization::skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) { foreach ($metrics['total'] as $metric) { $db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject; @@ -285,7 +285,7 @@ App::get('/v1/project/usage') }, $dbForProject->find('functions')); // This total is includes free and paid SMS usage - $authPhoneTotal = Authorization::skip(fn () => $dbForProject->sum('stats', 'value', [ + $authPhoneTotal = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->sum('stats', 'value', [ Query::equal('metric', [METRIC_AUTH_METHOD_PHONE]), Query::equal('period', ['1d']), Query::greaterThanEqual('time', $firstDay), @@ -293,7 +293,7 @@ App::get('/v1/project/usage') ])); // This estimate is only for paid SMS usage - $authPhoneMetrics = Authorization::skip(fn () => $dbForProject->find('stats', [ + $authPhoneMetrics = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('stats', [ Query::startsWith('metric', METRIC_AUTH_METHOD_PHONE . '.'), Query::equal('period', ['1d']), Query::greaterThanEqual('time', $firstDay), diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 8bc383cabd..ebccc9c321 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -31,7 +31,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; @@ -428,18 +428,17 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('deviceForLocal') ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceForFiles, Device $deviceForLocal) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $validator = new Authorization(Database::PERMISSION_CREATE); - if (!$validator->isValid($bucket->getCreate())) { - throw new Exception(Exception::USER_UNAUTHORIZED); + if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } $allowedPermissions = [ @@ -462,7 +461,7 @@ App::post('/v1/storage/buckets/:bucketId/files') } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -475,7 +474,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { + if (!$dbForProject->getAuthorization()->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -695,11 +694,10 @@ App::post('/v1/storage/buckets/:bucketId/files') * However as with chunk upload even if we are updating, we are essentially creating a file * adding it's new chunk so we validate create permission instead of update */ - $validator = new Authorization(Database::PERMISSION_CREATE); - if (!$validator->isValid($bucket->getCreate())) { - throw new Exception(Exception::USER_UNAUTHORIZED); + if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } - $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } } else { if ($file->isEmpty()) { @@ -738,13 +736,12 @@ App::post('/v1/storage/buckets/:bucketId/files') * However as with chunk upload even if we are updating, we are essentially creating a file * adding it's new chunk so we validate create permission instead of update */ - $validator = new Authorization(Database::PERMISSION_CREATE); - if (!$validator->isValid($bucket->getCreate())) { - throw new Exception(Exception::USER_UNAUTHORIZED); + if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } - + try { - $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -789,20 +786,19 @@ App::get('/v1/storage/buckets/:bucketId/files') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } $queries = Query::parseQueries($queries); @@ -831,7 +827,7 @@ App::get('/v1/storage/buckets/:bucketId/files') if ($fileSecurity && !$valid) { $cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($cursorDocument->isEmpty()) { @@ -848,8 +844,8 @@ App::get('/v1/storage/buckets/:bucketId/files') $files = $dbForProject->find('bucket_' . $bucket->getSequence(), $queries); $total = $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT); } else { - $files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); - $total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)); + $files = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); + $total = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -890,26 +886,25 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($file->isEmpty()) { @@ -972,10 +967,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') } /* @type Document $bucket */ - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -983,17 +978,16 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { @@ -1115,11 +1109,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; //Do not update transformedAt if it's a console user - if (!Auth::isPrivilegedUser(Authorization::getRoles())) { + if (!Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles())) { $transformedAt = $file->getAttribute('transformedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) { $file->setAttribute('transformedAt', DateTime::now()); - Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); } } @@ -1164,10 +1158,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->inject('deviceForFiles') ->action(function (string $bucketId, string $fileId, ?string $token, Request $request, Response $response, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) { /* @type Document $bucket */ - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1175,8 +1169,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -1185,7 +1178,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { @@ -1325,10 +1318,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->inject('deviceForFiles') ->action(function (string $bucketId, string $fileId, ?string $token, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) { /* @type Document $bucket */ - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1336,8 +1329,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -1346,7 +1338,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { @@ -1479,7 +1471,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->inject('mode') ->inject('deviceForFiles') ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Document $project, string $mode, Device $deviceForFiles) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $decoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0); @@ -1497,14 +1489,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') throw new Exception(Exception::USER_UNAUTHORIZED); } - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1652,24 +1644,23 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('queueForEvents') ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $queueForEvents) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_UPDATE); - $valid = $validator->isValid($bucket->getUpdate()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } // Read permission should not be required for update - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1683,7 +1674,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ]); // Users can only manage their own roles, API keys and Admin users can manage any - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -1696,7 +1687,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { + if (!$dbForProject->getAuthorization()->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -1717,7 +1708,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $file = $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file); } else { - $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1766,32 +1757,32 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('deviceForFiles') ->inject('queueForDeletes') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceForFiles, Delete $queueForDeletes) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_DELETE); - $valid = $validator->isValid($bucket->getDelete()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_DELETE, $bucket->getDelete())); if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for delete - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } // Make sure we don't delete the file before the document permission check occurs - if ($fileSecurity && !$valid && !$validator->isValid($file->getDelete())) { - throw new Exception(Exception::USER_UNAUTHORIZED); + $validFile = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_DELETE, $file->getDelete())); + if ($fileSecurity && !$valid && !$validFile) { + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } $deviceDeleted = false; @@ -1815,7 +1806,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId)); + $deleted = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1872,7 +1863,7 @@ App::get('/v1/storage/usage') ]; $total = []; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), @@ -1968,7 +1959,7 @@ App::get('/v1/storage/:bucketId/usage') str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED), ]; - Authorization::skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $db = ($metric === str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED)) ? $dbForLogs diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 7398e451b5..eb70282ff4 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -85,13 +85,13 @@ App::post('/v1/teams') ->inject('queueForEvents') ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $isAppUser = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAppUser = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; try { - $team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([ + $team = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('teams', new Document([ '$id' => $teamId, '$permissions' => [ Permission::read(Role::team($teamId)), @@ -494,8 +494,8 @@ App::post('/v1/teams/:teamId/memberships') ->inject('queueForStatsUsage') ->inject('plan') ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { - $isAppUser = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAppUser = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); $url = htmlentities($url); if (empty($url)) { @@ -566,7 +566,7 @@ App::post('/v1/teams/:teamId/memberships') try { $userId = ID::unique(); - $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ + $invitee = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -602,7 +602,7 @@ App::post('/v1/teams/:teamId/memberships') } } - $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + $isOwner = $dbForProject->getAuthorization()->hasRole('team:' . $team->getId() . '/owner'); if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team'); @@ -638,11 +638,11 @@ App::post('/v1/teams/:teamId/memberships') ]); $membership = ($isPrivilegedUser || $isAppUser) ? - Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)) : + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('memberships', $membership)) : $dbForProject->createDocument('memberships', $membership); if ($isPrivilegedUser || $isAppUser) { - Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); } } elseif ($membership->getAttribute('confirm') === false) { @@ -655,7 +655,7 @@ App::post('/v1/teams/:teamId/memberships') } $membership = ($isPrivilegedUser || $isAppUser) ? - Authorization::skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) : + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) : $dbForProject->updateDocument('memberships', $membership->getId(), $membership); } else { throw new Exception(Exception::MEMBERSHIP_ALREADY_CONFIRMED); @@ -911,7 +911,7 @@ App::get('/v1/teams/:teamId/memberships') 'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true, ]; - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -1002,7 +1002,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') 'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true, ]; - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -1099,9 +1099,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::USER_NOT_FOUND); } - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $isAppUser = Auth::isAppUser(Authorization::getRoles()); - $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAppUser = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isOwner = $dbForProject->getAuthorization()->hasRole('team:' . $team->getId() . '/owner'); if ($project->getId() === 'console') { // Quick check: fetch up to 2 owners to determine if only one exists @@ -1194,7 +1194,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') throw new Exception(Exception::MEMBERSHIP_NOT_FOUND); } - $team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId)); + $team = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -1230,11 +1230,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->setAttribute('confirm', true) ; - Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); // Create session for the user if not logged in if (!$hasSession) { - Authorization::setRole(Role::user($user->getId())->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); $detector = new Detector($request->getUserAgent('UNKNOWN')); $record = $geodb->get($request->getIP()); @@ -1262,7 +1262,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $session = $dbForProject->createDocument('sessions', $session); - Authorization::setRole(Role::user($userId)->toString()); + $dbForProject->getAuthorization()->addRole(Role::user($userId)->toString()); if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); @@ -1295,7 +1295,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $dbForProject->purgeCachedDocument('users', $user->getId()); - Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); $queueForEvents ->setParam('userId', $user->getId()) @@ -1398,7 +1398,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $dbForProject->purgeCachedDocument('users', $profile->getId()); if ($membership->getAttribute('confirm')) { // Count only confirmed members - Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); } $queueForEvents diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 5498a33bf5..9c7cd75817 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2629,7 +2629,7 @@ App::get('/v1/users/usage') METRIC_SESSIONS, ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $count => $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 5bda9961f3..564f6e5493 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -73,12 +73,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId } $projectId = $repository->getAttribute('projectId'); - $project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); $dbForProject = $getProjectDB($project); $resourceCollection = $resourceType === "function" ? 'functions' : 'sites'; $resourceId = $repository->getAttribute('resourceId'); - $resource = Authorization::skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId)); + $resource = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId)); $resourceInternalId = $resource->getSequence(); $deploymentId = ID::unique(); @@ -127,7 +127,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = ''; if (!empty($providerPullRequestId) && $resource->getAttribute('providerSilentMode', false) === false) { - $latestComment = Authorization::skip(fn () => $dbForPlatform->findOne('vcsComments', [ + $latestComment = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('vcsComments', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::equal('providerPullRequestId', [$providerPullRequestId]), Query::orderDesc('$createdAt'), @@ -177,7 +177,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId if (!empty($latestCommentId)) { $teamId = $project->getAttribute('teamId', ''); - $latestComment = Authorization::skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([ + $latestComment = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([ '$id' => ID::unique(), '$permissions' => [ Permission::read(Role::team(ID::custom($teamId))), @@ -198,7 +198,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId } } } elseif (!empty($providerBranch)) { - $latestComments = Authorization::skip(fn () => $dbForPlatform->find('vcsComments', [ + $latestComments = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('vcsComments', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::equal('providerBranch', [$providerBranch]), Query::orderDesc('$createdAt'), @@ -280,7 +280,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $commands[] = $resource->getAttribute('commands', ''); } - $deployment = Authorization::skip(fn () => $dbForProject->createDocument('deployments', new Document([ + $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('deployments', new Document([ '$id' => $deploymentId, '$permissions' => [ Permission::read(Role::any()), @@ -320,7 +320,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId ->setAttribute('latestDeploymentInternalId', $deployment->getSequence()) ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); - Authorization::skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource)); if ($resource->getCollection() === 'sites') { $projectId = $project->getId(); @@ -330,7 +330,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = ID::unique() . "." . $sitesDomain; $ruleId = md5($domain); $previewRuleId = $ruleId; - Authorization::skip( + $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -363,7 +363,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - Authorization::skip( + $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -394,7 +394,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = "commit-" . substr($providerCommitHash, 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - Authorization::skip( + $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -446,7 +446,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId if ($lockAcquired) { // Wrap in try/finally to ensure lock file gets deleted try { - $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId)); + $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId)); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https'; $previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : ''; @@ -1345,7 +1345,7 @@ App::post('/v1/vcs/github/events') $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); //find resourceId from relevant resources table - $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::limit(100), ])); @@ -1365,13 +1365,13 @@ App::post('/v1/vcs/github/events') ]); foreach ($installations as $installation) { - $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('installationInternalId', [$installation->getSequence()]), Query::limit(1000) ])); foreach ($repositories as $repository) { - Authorization::skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId())); + $dbForProject->getAuthorization()->skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId())); } $dbForPlatform->deleteDocument('installations', $installation->getId()); @@ -1403,7 +1403,7 @@ App::post('/v1/vcs/github/events') $providerCommitAuthor = $commitDetails["commitAuthor"] ?? ''; $providerCommitMessage = $commitDetails["commitMessage"] ?? ''; - $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::orderDesc('$createdAt') ])); @@ -1417,7 +1417,7 @@ App::post('/v1/vcs/github/events') $external = $parsedPayload["external"] ?? true; if ($external) { - $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::orderDesc('$createdAt') ])); @@ -1428,7 +1428,7 @@ App::post('/v1/vcs/github/events') if (\in_array($providerPullRequestId, $providerPullRequestIds)) { $providerPullRequestIds = \array_diff($providerPullRequestIds, [$providerPullRequestId]); $repository = $repository->setAttribute('providerPullRequestIds', $providerPullRequestIds); - $repository = Authorization::skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); + $repository = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); } } } @@ -1624,7 +1624,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor throw new Exception(Exception::INSTALLATION_NOT_FOUND); } - $repository = Authorization::skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [ + $repository = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [ Query::equal('projectInternalId', [$project->getSequence()]) ])); @@ -1641,7 +1641,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor // TODO: Delete from array when PR is closed - $repository = Authorization::skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); + $repository = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); $privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); $githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID'); diff --git a/app/controllers/general.php b/app/controllers/general.php index 07de95a38f..b6452abd7f 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -65,9 +65,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw // TODO: @christyjacob remove once we migrate the rules in 1.7.x if (System::getEnv('_APP_RULES_FORMAT') === 'md5') { - $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($host))); + $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('rules', md5($host))); } else { - $rule = Authorization::skip( + $rule = $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->find('rules', [ Query::equal('domain', [$host]), Query::limit(1) @@ -108,7 +108,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $projectId = $rule->getAttribute('projectId'); - $project = Authorization::skip( + $project = $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->getDocument('projects', $projectId) ); @@ -116,7 +116,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } /** @@ -155,7 +155,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw /** @var Document $deployment */ if (!empty($rule->getAttribute('deploymentId', ''))) { - $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); + $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); } else { // 1.6.x DB schema compatibility // TODO: Make sure deploymentId is never empty, and remove this code @@ -169,15 +169,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw // Document of site or function $resource = $resourceType === 'function' ? - Authorization::skip(fn () => $dbForProject->getDocument('functions', $resourceId)) : - Authorization::skip(fn () => $dbForProject->getDocument('sites', $resourceId)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $resourceId)) : + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('sites', $resourceId)); // ID of active deployments // Attempts to use attribute from both schemas (1.6 and 1.7) $activeDeploymentId = $resource->getAttribute('deploymentId', $resource->getAttribute('deployment', '')); // Get deployment document, as intended originally - $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId)); + $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId)); } if ($deployment->getAttribute('resourceType', '') === 'functions') { @@ -196,8 +196,8 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $resource = $type === 'function' ? - Authorization::skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) : - Authorization::skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', ''))); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) : + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', ''))); $isPreview = $type === 'function' ? false : ($rule->getAttribute('trigger', '') !== 'manual'); @@ -239,7 +239,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw $userExists = false; $userId = $payload['userId'] ?? ''; if (!empty($userId)) { - $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if (!$user->isEmpty() && $user->getAttribute('status', false)) { $userExists = true; } @@ -252,7 +252,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $membershipExists = false; - $project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); if (!$project->isEmpty() && isset($user)) { $teamId = $project->getAttribute('teamId', ''); $membership = $user->find('teamId', $teamId, 'memberships'); @@ -919,7 +919,7 @@ App::init() } elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) { Console::warning('Skipping SSL certificates generation on ACME challenge.'); } else { - Authorization::disable(); + $dbForPlatform->getAuthorization()->disable(); $envDomain = System::getEnv('_APP_DOMAIN', ''); $mainDomain = null; @@ -989,7 +989,7 @@ App::init() } $domains[$domain->get()] = true; - Authorization::reset(); // ensure authorization is re-enabled + $dbForPlatform->getAuthorization()->reset(); // ensure authorization is re-enabled } Config::setParam('domains', $domains); } @@ -1174,7 +1174,8 @@ App::error() ->inject('log') ->inject('queueForStatsUsage') ->inject('devKey') - ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage) { + ->inject('authorization') + ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage, Authorization $authorization) { $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); $route = $utopia->getRoute(); $class = \get_class($error); @@ -1256,7 +1257,7 @@ App::error() * If not a publishable error, track usage stats. Publishable errors are >= 500 or those explicitly marked as publish=true in errors.php */ if (!$publish && $project->getId() !== 'console') { - if (!Auth::isPrivilegedUser(Authorization::getRoles())) { + if (!Auth::isPrivilegedUser($authorization->getRoles())) { $fileSize = 0; $file = $request->getFiles('file'); if (!empty($file)) { @@ -1318,7 +1319,7 @@ App::error() $log->addExtra('file', $error->getFile()); $log->addExtra('line', $error->getLine()); $log->addExtra('trace', $error->getTraceAsString()); - $log->addExtra('roles', Authorization::getRoles()); + $log->addExtra('roles', $authorization->getRoles()); $action = 'UNKNOWN_NAMESPACE.UNKNOWN.METHOD'; if (!empty($sdk)) { @@ -1580,7 +1581,7 @@ App::get('/v1/ping') ->setAttribute('pingCount', $pingCount) ->setAttribute('pingedAt', $pingedAt); - Authorization::skip(function () use ($dbForPlatform, $project) { + $dbForPlatform->getAuthorization()->skip(function () use ($dbForPlatform, $project) { $dbForPlatform->updateDocument('projects', $project->getId(), $project); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 959ee77b7d..113b665925 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -28,7 +28,7 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Queue\Publisher; use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; @@ -249,7 +249,7 @@ App::init() if ($apiKey->getRole() === Auth::USER_ROLE_APPS) { // Disable authorization checks for API keys - Authorization::setDefaultStatus(false); + $dbForPlatform->getAuthorization()->setDefaultStatus(false); $user = new Document([ '$id' => '', @@ -322,14 +322,14 @@ App::init() $scopes = \array_merge($scopes, $roles[$role]['scopes']); } - Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. + $dbForPlatform->getAuthorization()->setDefaultStatus(false); // Cancel security segmentation for admin users. } $scopes = \array_unique($scopes); - Authorization::setRole($role); - foreach (Auth::getRoles($user) as $authRole) { - Authorization::setRole($authRole); + $dbForPlatform->getAuthorization()->addRole($role); + foreach (Auth::getRoles($user, $dbForPlatform->getAuthorization()) as $authRole) { + $dbForPlatform->getAuthorization()->addRole($authRole); } // Update project last activity @@ -337,7 +337,7 @@ App::init() $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } } @@ -372,7 +372,7 @@ App::init() if ( array_key_exists($namespace, $project->getAttribute('services', [])) && !$project->getAttribute('services', [])[$namespace] - && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) + && !(Auth::isPrivilegedUser($dbForPlatform->getAuthorization()->getRoles()) || Auth::isAppUser($dbForPlatform->getAuthorization()->getRoles())) ) { throw new Exception(Exception::GENERAL_SERVICE_DISABLED); } @@ -439,7 +439,7 @@ App::init() if ( array_key_exists('rest', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['rest'] - && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) + && !(Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()) || Auth::isAppUser($dbForProject->getAuthorization() ->getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } @@ -469,7 +469,7 @@ App::init() $closestLimit = null; - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -569,10 +569,10 @@ App::init() if ($useCache) { $route = $utopia->match($request); $isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview'; - $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser(Authorization::getRoles()); + $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); $key = $request->cacheIdentifier(); - $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('cache', $key)); $cache = new Cache( new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); @@ -585,18 +585,17 @@ App::init() if ($type === 'bucket' && (!$isImageTransformation || !$isDisabled)) { $bucketId = $parts[1] ?? null; - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); + $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -607,7 +606,7 @@ App::init() if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { @@ -618,11 +617,11 @@ App::init() throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } //Do not update transformedAt if it's a console user - if (!Auth::isPrivilegedUser(Authorization::getRoles())) { + if (!Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles())) { $transformedAt = $file->getAttribute('transformedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) { $file->setAttribute('transformedAt', DateTime::now()); - Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); } } } @@ -844,11 +843,11 @@ App::shutdown() $key = $request->cacheIdentifier(); $signature = md5($data['payload']); - $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('cache', $key)); $accessedAt = $cacheLog->getAttribute('accessedAt', 0); $now = DateTime::now(); if ($cacheLog->isEmpty()) { - Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('cache', new Document([ '$id' => $key, 'resource' => $resource, 'resourceType' => $resourceType, @@ -858,7 +857,7 @@ App::shutdown() ]))); } elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) { $cacheLog->setAttribute('accessedAt', $now); - Authorization::skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog)); // Overwrite the file every APP_CACHE_UPDATE seconds to update the file modified time that is used in the TTL checks in cache->load() $cache->save($key, $data['payload']); } @@ -870,7 +869,7 @@ App::shutdown() } if ($project->getId() !== 'console') { - if (!Auth::isPrivilegedUser(Authorization::getRoles())) { + if (!Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles())) { $fileSize = 0; $file = $request->getFiles('file'); if (!empty($file)) { diff --git a/app/controllers/shared/api/auth.php b/app/controllers/shared/api/auth.php index ecabc641ec..0e3c89c19a 100644 --- a/app/controllers/shared/api/auth.php +++ b/app/controllers/shared/api/auth.php @@ -36,7 +36,8 @@ App::init() ->inject('request') ->inject('project') ->inject('geodb') - ->action(function (App $utopia, Request $request, Document $project, Reader $geodb) { + ->inject('authorization') + ->action(function (App $utopia, Request $request, Document $project, Reader $geodb, Authorization $authorization) { $denylist = System::getEnv('_APP_CONSOLE_COUNTRIES_DENYLIST', ''); if (!empty($denylist && $project->getId() === 'console')) { $countries = explode(',', $denylist); @@ -49,8 +50,8 @@ App::init() $route = $utopia->match($request); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $isAppUser = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAppUser = Auth::isAppUser($authorization->getRoles()); if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs return; diff --git a/app/http.php b/app/http.php index 1bd3e97e69..0f65bb6606 100644 --- a/app/http.php +++ b/app/http.php @@ -318,9 +318,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes); } - if (Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { + if ($dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { Console::info(" └── Creating screenshots bucket..."); - Authorization::skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ '$id' => ID::custom('screenshots'), '$collection' => ID::custom('buckets'), 'name' => 'Screenshots', @@ -335,7 +335,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg 'search' => 'buckets Screenshots', ]))); - $bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); Console::info(" └── Creating files collection for screenshots bucket..."); $files = $collections['buckets']['files'] ?? []; @@ -363,7 +363,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg 'orders' => $index['orders'], ]), $files['indexes']); - Authorization::skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes)); } }); @@ -454,8 +454,13 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool App::setResource('pools', fn () => $pools); try { - Authorization::cleanRoles(); - Authorization::setRole(Role::any()->toString()); + $authorization = $app->getResource('authorization'); + + $request->setAuthorization($authorization); + $response->setAuthorization($authorization); + + $authorization->cleanRoles(); + $authorization->addRole(Role::any()->toString()); $app->run($request, $response); } catch (\Throwable $th) { @@ -497,7 +502,7 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool $log->addExtra('file', $th->getFile()); $log->addExtra('line', $th->getLine()); $log->addExtra('trace', $th->getTraceAsString()); - $log->addExtra('roles', Authorization::getRoles()); + $log->addExtra('roles', $authorization->getRoles()); $sdk = $route->getLabel("sdk", false); @@ -573,7 +578,7 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) { } $results = []; try { - $results = Authorization::skip(fn () => $dbForPlatform->find('rules', $queries)); + $results = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('rules', $queries)); } catch (Throwable $th) { Console::error($th->getMessage()); } diff --git a/app/init/database/filters.php b/app/init/database/filters.php index c4cfd1ac81..1e2f458724 100644 --- a/app/init/database/filters.php +++ b/app/init/database/filters.php @@ -176,7 +176,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database->find('sessions', [ + return $database->getAuthorization()->skip(fn () => $database->find('sessions', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), ])); @@ -189,7 +189,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return $database->getAuthorization()->skip(fn () => $database ->find('tokens', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -203,7 +203,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return $database->getAuthorization()->skip(fn () => $database ->find('challenges', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -217,7 +217,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return $database->getAuthorization()->skip(fn () => $database ->find('authenticators', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -231,7 +231,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return $database->getAuthorization()->skip(fn () => $database ->find('memberships', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -331,7 +331,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return $database->getAuthorization()->skip(fn () => $database ->find('targets', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY) @@ -345,7 +345,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - $targetIds = Authorization::skip(fn () => \array_map( + $targetIds = $database->getAuthorization()->skip(fn () => \array_map( fn ($document) => $document->getAttribute('targetInternalId'), $database->find('subscribers', [ Query::equal('topicInternalId', [$document->getSequence()]), diff --git a/app/init/resources.php b/app/init/resources.php index f91d18f698..2d5d8059a6 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -200,9 +200,9 @@ App::setResource('platforms', function (Request $request, Document $console, Doc // Safe if rule with same project ID exists if (!empty($origin)) { if (System::getEnv('_APP_RULES_FORMAT') === 'md5') { - $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? ''))); + $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? ''))); } else { - $rule = Authorization::skip( + $rule = $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->find('rules', [ Query::equal('domain', [$origin]), Query::limit(1) @@ -232,9 +232,10 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons /** @var Utopia\Database\Document $project */ /** @var Utopia\Database\Database $dbForProject */ /** @var Utopia\Database\Database $dbForPlatform */ + /** @var Utopia\Database\Authorization $authorization */ /** @var string $mode */ - Authorization::setDefaultStatus(true); + $dbForPlatform->getAuthorization()->setDefaultStatus(true); Auth::setCookieName('a_session_' . $project->getId()); @@ -349,7 +350,7 @@ App::setResource('project', function ($dbForPlatform, $request, $console) { return $console; } - $project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); return $project; }, ['dbForPlatform', 'request', 'console']); @@ -379,7 +380,11 @@ App::setResource('console', function () { return new Document(Config::getParam('console')); }, []); -App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project) { +App::setResource('authorization', function () { + return new Authorization(); +}, []); + +App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project, Authorization $authorization) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -395,6 +400,7 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform $database = new Database($adapter, $cache); $database + ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()) ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) @@ -415,13 +421,14 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform } return $database; -}, ['pools', 'dbForPlatform', 'cache', 'project']); +}, ['pools', 'dbForPlatform', 'cache', 'project', 'authorization']); -App::setResource('dbForPlatform', function (Group $pools, Cache $cache) { +App::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authorization $authorization) { $adapter = new DatabasePool($pools->get('console')); $database = new Database($adapter, $cache); $database + ->setAuthorization($authorization) ->setNamespace('_console') ->setMetadata('host', \gethostname()) ->setMetadata('project', 'console') @@ -429,12 +436,12 @@ App::setResource('dbForPlatform', function (Group $pools, Cache $cache) { ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); return $database; -}, ['pools', 'cache']); +}, ['pools', 'cache', 'authorization']); -App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) { +App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, Authorization $authorization) { $databases = []; - return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) { + return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -446,8 +453,9 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $dsn = new DSN('mysql://' . $project->getAttribute('database')); } - $configure = (function (Database $database) use ($project, $dsn) { + $configure = (function (Database $database) use ($project, $dsn, $authorization) { $database + ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()) ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) @@ -481,12 +489,12 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform return $database; }; -}, ['pools', 'dbForPlatform', 'cache']); +}, ['pools', 'dbForPlatform', 'cache', 'authorization']); -App::setResource('getLogsDB', function (Group $pools, Cache $cache) { +App::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { $database = null; - return function (?Document $project = null) use ($pools, $cache, &$database) { + return function (?Document $project = null) use ($pools, $cache, $authorization, &$database) { if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') { $database->setTenant((int) $project->getSequence()); return $database; @@ -496,6 +504,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database = new Database($adapter, $cache); $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) @@ -508,7 +517,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) { return $database; }; -}, ['pools', 'cache']); +}, ['pools', 'cache', 'authorization']); App::setResource('telemetry', fn () => new NoTelemetry()); @@ -713,7 +722,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { }; $attributes = function (int $limit, int $offset) use ($dbForProject) { - $attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [ + $attrs = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('attributes', [ Query::limit($limit), Query::offset($offset), ])); @@ -852,7 +861,7 @@ App::setResource('devKey', function (Request $request, Document $project, array $accessedAt = $key->getAttribute('accessedAt', 0); if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) { $key->setAttribute('accessedAt', DatabaseDateTime::now()); - Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); $dbForPlatform->purgeCachedDocument('projects', $project->getId()); } @@ -869,7 +878,7 @@ App::setResource('devKey', function (Request $request, Document $project, array /** Update access time as well */ $key->setAttribute('accessedAt', DatabaseDateTime::now()); - $key = Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); + $key = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); $dbForPlatform->purgeCachedDocument('projects', $project->getId()); } } @@ -886,7 +895,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A if (str_starts_with($path, '/v1/projects/:projectId')) { $uri = $request->getURI(); $pid = explode('/', $uri)[3]; - $p = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $pid)); + $p = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $pid)); $teamInternalId = $p->getAttribute('teamInternalId', ''); } elseif ($path === '/v1/projects') { $teamId = $request->getParam('teamId', ''); @@ -895,7 +904,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A return new Document([]); } - $team = Authorization::skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); + $team = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); return $team; } } @@ -904,7 +913,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A return new Document([]); } - $team = Authorization::skip(function () use ($dbForPlatform, $teamInternalId) { + $team = $dbForPlatform->getAuthorization()->skip(function () use ($dbForPlatform, $teamInternalId) { return $dbForPlatform->findOne('teams', [ Query::equal('$sequence', [$teamInternalId]), ]); @@ -966,7 +975,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) { return new Document([]); } - $token = Authorization::skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId)); + $token = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId)); if ($token->isEmpty()) { return new Document([]); @@ -995,7 +1004,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) { $accessedAt = $token->getAttribute('accessedAt', 0); if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_RESOURCE_TOKEN_ACCESS)) > $accessedAt) { $token->setAttribute('accessedAt', DatabaseDateTime::now()); - Authorization::skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token)); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token)); } return new Document([ diff --git a/app/realtime.php b/app/realtime.php index e18ab8e10d..e70b0a152d 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -28,7 +28,6 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; use Utopia\Logger\Log; use Utopia\Pools\Group; @@ -299,7 +298,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume 'value' => '{}' ]); - $statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document)); + $statsDocument = $database->getAuthorization()->skip(fn () => $database->createDocument('realtime', $document)); break; } catch (Throwable) { Console::warning("Collection not ready. Retrying connection ({$attempts})..."); @@ -329,7 +328,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume ->setAttribute('timestamp', DateTime::now()) ->setAttribute('value', json_encode($payload)); - Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); + $database->getAuthorization()->skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); } catch (Throwable $th) { $logError($th, "updateWorkerDocument"); } @@ -360,7 +359,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $payload = []; - $list = Authorization::skip(fn () => $database->find('realtime', [ + $list = $database->getAuthorization()->skip(fn () => $database->find('realtime', [ Query::greaterThan('timestamp', DateTime::addSeconds(new \DateTime(), -15)), ])); @@ -454,12 +453,12 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); $consoleDatabase = getConsoleDB(); - $project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); + $project = $consoleDatabase->getAuthorization()->skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); $database = getProjectDB($project); $user = $database->getDocument('users', $userId); - $roles = Auth::getRoles($user); + $roles = $consoleDatabase->getAuthorization()->getRoles($user); $channels = $realtime->connections[$connection]['channels']; $realtime->unsubscribe($connection); @@ -515,6 +514,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, try { /** @var Document $project */ $project = $app->getResource('project'); + $authorization = $app->getResource('authorization'); /* * Project Check @@ -526,7 +526,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, if ( array_key_exists('realtime', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['realtime'] - && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) + && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } @@ -563,7 +563,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, throw new Exception(Exception::REALTIME_POLICY_VIOLATION, $originValidator->getDescription()); } - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $authorization); $channels = Realtime::convertChannels($request->getQuery('channels', []), $user->getId()); @@ -637,8 +637,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $database = getConsoleDB(); if ($projectId !== 'console') { - $project = Authorization::skip(fn () => $database->getDocument('projects', $projectId)); - $database = getProjectDB($project); + $project = $database->getAuthorization()->skip(fn () => $database->getDocument('projects', $projectId)); + $database = getProjectDB($project, $database->getAuthorization()); } else { $project = null; } @@ -692,7 +692,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Session is not valid.'); } - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $database->getAuthorization()); $channels = Realtime::convertChannels(array_flip($realtime->connections[$connection]['channels']), $user->getId()); $realtime->subscribe($realtime->connections[$connection]['projectId'], $connection, $roles, $channels); diff --git a/app/worker.php b/app/worker.php index bf0a6583ec..c5dcb14a1e 100644 --- a/app/worker.php +++ b/app/worker.php @@ -45,19 +45,24 @@ use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; use Utopia\Telemetry\Adapter\None as NoTelemetry; -Authorization::disable(); Runtime::enableCoroutine(); Server::setResource('register', fn () => $register); -Server::setResource('dbForPlatform', function (Cache $cache, Registry $register) { +Server::setResource('authorization', function () { + $authorization = new Authorization(); + return $authorization; +}, []); + +Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, Authorization $authorization) { $pools = $register->get('pools'); $adapter = new DatabasePool($pools->get('console')); $dbForPlatform = new Database($adapter, $cache); $dbForPlatform->setNamespace('_console'); + $dbForPlatform->setAuthorization($authorization); return $dbForPlatform; -}, ['cache', 'register']); +}, ['cache', 'register', 'authorization']); Server::setResource('project', function (Message $message, Database $dbForPlatform) { $payload = $message->getPayload() ?? []; @@ -70,7 +75,7 @@ Server::setResource('project', function (Message $message, Database $dbForPlatfo return $dbForPlatform->getDocument('projects', $project->getId()); }, ['message', 'dbForPlatform']); -Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForPlatform) { +Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForPlatform, Authorization $authorization) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -91,11 +96,13 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, if (\in_array($dsn->getHost(), $sharedTables)) { $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database + ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -104,12 +111,12 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); return $database; -}, ['cache', 'register', 'message', 'project', 'dbForPlatform']); +}, ['cache', 'register', 'message', 'project', 'dbForPlatform', 'authorization']); -Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) { +Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, Authorization $authorization) { $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools - return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases): Database { + return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases): Database { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -128,11 +135,13 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf if (\in_array($dsn->getHost(), $sharedTables)) { $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database + ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -150,11 +159,13 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf if (\in_array($dsn->getHost(), $sharedTables)) { $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database + ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -164,11 +175,11 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf return $database; }; -}, ['pools', 'dbForPlatform', 'cache']); +}, ['pools', 'dbForPlatform', 'cache', 'authorization']); -Server::setResource('getLogsDB', function (Group $pools, Cache $cache) { +Server::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { $database = null; - return function (?Document $project = null) use ($pools, $cache, $database) { + return function (?Document $project = null) use ($pools, $cache, $database, $authorization) { if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') { $database->setTenant((int)$project->getSequence()); return $database; @@ -178,6 +189,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database = new Database($adapter, $cache); $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER) @@ -190,7 +202,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) { return $database; }; -}, ['pools', 'cache']); +}, ['pools', 'cache', 'authorization']); Server::setResource('abuseRetention', function () { return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400); // 1 day @@ -478,7 +490,8 @@ $worker ->inject('log') ->inject('pools') ->inject('project') - ->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project) use ($worker, $queueName) { + ->inject('authorization') + ->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project, Authorization $authorization) use ($worker, $queueName) { $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); if ($logger) { @@ -494,7 +507,7 @@ $worker $log->addExtra('file', $error->getFile()); $log->addExtra('line', $error->getLine()); $log->addExtra('trace', $error->getTraceAsString()); - $log->addExtra('roles', Authorization::getRoles()); + $log->addExtra('roles', $authorization->getRoles()); $isProduction = System::getEnv('_APP_ENV', 'development') === 'production'; $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); diff --git a/composer.json b/composer.json index bb843fd771..6f408a72f7 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "utopia-php/cache": "0.13.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "3.*", + "utopia-php/database": "dev-feat-authorization-instance as 3.0.2", "utopia-php/detector": "0.1.*", "utopia-php/domains": "0.8.*", "utopia-php/dns": "0.3.*", diff --git a/composer.lock b/composer.lock index c4a8b67561..68c88b9c73 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": "407c1717bfef580d733ff2bbb232ec8a", + "content-hash": "f27ea68014d28d445baa355466cdb7a9", "packages": [ { "name": "adhocore/jwt", @@ -3791,17 +3791,65 @@ "time": "2020-10-24T09:49:09+00:00" }, { - "name": "utopia-php/database", - "version": "3.0.2", + "name": "utopia-php/console", + "version": "0.0.1", "source": { "type": "git", - "url": "https://github.com/utopia-php/database.git", - "reference": "b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e" + "url": "https://github.com/utopia-php/console.git", + "reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e", - "reference": "b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e", + "url": "https://api.github.com/repos/utopia-php/console/zipball/f77104e4a888fa9cb3e08f32955ec09479ab7a92", + "reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.3", + "squizlabs/php_codesniffer": "^3.6", + "swoole/ide-helper": "4.8.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Console helpers for logging, prompting, and executing commands", + "keywords": [ + "cli", + "console", + "php", + "terminal", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/console/issues", + "source": "https://github.com/utopia-php/console/tree/0.0.1" + }, + "time": "2025-10-20T14:41:36+00:00" + }, + { + "name": "utopia-php/database", + "version": "dev-feat-authorization-instance", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/database.git", + "reference": "4088c1002bbc837fd9299987cce5d460ded210d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/database/zipball/4088c1002bbc837fd9299987cce5d460ded210d1", + "reference": "4088c1002bbc837fd9299987cce5d460ded210d1", "shasum": "" }, "require": { @@ -3844,9 +3892,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.0.2" + "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance" }, - "time": "2025-10-20T23:58:56+00:00" + "time": "2025-10-20T13:53:53+00:00" }, { "name": "utopia-php/detector", @@ -4346,16 +4394,16 @@ }, { "name": "utopia-php/migration", - "version": "1.2.2", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "e0b6687620dd67fe2b96eb4419e8243577b11c8f" + "reference": "b6985b235ab64f07a6b88569e20cf9b2df7d838c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/e0b6687620dd67fe2b96eb4419e8243577b11c8f", - "reference": "e0b6687620dd67fe2b96eb4419e8243577b11c8f", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/b6985b235ab64f07a6b88569e20cf9b2df7d838c", + "reference": "b6985b235ab64f07a6b88569e20cf9b2df7d838c", "shasum": "" }, "require": { @@ -4363,9 +4411,9 @@ "ext-curl": "*", "ext-openssl": "*", "php": ">=8.1", + "utopia-php/console": "0.0.*", "utopia-php/database": "3.*", "utopia-php/dsn": "0.2.*", - "utopia-php/framework": "0.33.*", "utopia-php/storage": "0.18.*" }, "require-dev": { @@ -4373,7 +4421,6 @@ "laravel/pint": "1.*", "phpstan/phpstan": "1.*", "phpunit/phpunit": "11.*", - "utopia-php/cli": "0.16.*", "vlucas/phpdotenv": "5.*" }, "type": "library", @@ -4396,9 +4443,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.2.2" + "source": "https://github.com/utopia-php/migration/tree/1.3.1" }, - "time": "2025-10-20T10:12:11+00:00" + "time": "2025-10-21T08:13:54+00:00" }, { "name": "utopia-php/mongo", @@ -8736,9 +8783,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-feat-authorization-instance", + "alias": "3.0.2", + "alias_normalized": "3.0.2.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8762,5 +8818,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.2.0" } diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index 9af5045fa4..b6676a2843 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -453,11 +453,11 @@ class Auth * @param Document $user * @return array */ - public static function getRoles(Document $user): array + public static function getRoles(Document $user, Authorization $authorization): array { $roles = []; - if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) { + if (!self::isPrivilegedUser($authorization->getRoles()) && !self::isAppUser($authorization->getRoles())) { if ($user->getId()) { $roles[] = Role::user($user->getId())->toString(); $roles[] = Role::users()->toString(); diff --git a/src/Appwrite/Databases/TransactionState.php b/src/Appwrite/Databases/TransactionState.php index 23dc6fc2e9..123e2f767f 100644 --- a/src/Appwrite/Databases/TransactionState.php +++ b/src/Appwrite/Databases/TransactionState.php @@ -342,12 +342,12 @@ class TransactionState */ private function getTransactionState(string $transactionId): array { - $transaction = Authorization::skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId)); + $transaction = $this->dbForProject->getAuthorization()->skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId)); if ($transaction->isEmpty() || $transaction->getAttribute('status') !== 'pending') { return []; } - $operations = Authorization::skip(fn () => $this->dbForProject->find('transactionLogs', [ + $operations =$this->dbForProject->getAuthorization()->skip(fn () => $this->dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX) diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 2d82b9c486..f338b2ab29 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -99,8 +99,6 @@ abstract class Migration public function __construct() { - Authorization::disable(); - Authorization::setDefaultStatus(false); $this->collections = Config::getParam('collections', []); @@ -135,6 +133,9 @@ abstract class Migration $this->dbForPlatform = $dbForPlatform; $this->getProjectDB = $getProjectDB; + $this->dbForPlatform->getAuthorization()->disable(); + $this->dbForPlatform->getAuthorization()->setDefaultStatus(false); + return $this; } diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 92805fbaf8..168ee7fc79 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -205,7 +205,7 @@ class Base extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - Authorization::skip( + $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -231,7 +231,7 @@ class Base extends Action $domain = "commit-" . substr($commitDetails['commitHash'], 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - Authorization::skip( + $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -268,7 +268,7 @@ class Base extends Action $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - Authorization::skip( + $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php index b67a42adb1..3bb49e7142 100644 --- a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php +++ b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php @@ -124,7 +124,7 @@ class Get extends Action throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.'); } - $document = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ + $document = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal('domain', [$value]), ])); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php index 48124e2a11..9e014fd083 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php @@ -310,7 +310,7 @@ abstract class Action extends UtopiaAction throw new Exception($this->getSpatialTypeNotSupportedException()); } - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -371,7 +371,7 @@ abstract class Action extends UtopiaAction \in_array($attribute->getAttribute('type'), Database::SPATIAL_TYPES) && $attribute->getAttribute('required') ) { - $hasData = !Authorization::skip(fn () => $dbForProject + $hasData = !$dbForProject->getAuthorization()->skip(fn () => $dbForProject ->findOne('database_' . $db->getSequence() . '_collection_' . $collection->getSequence())) ->isEmpty(); @@ -474,7 +474,7 @@ abstract class Action extends UtopiaAction protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, string $type, int $size = null, string $filter = null, string|bool|int|float|array $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php index eb51044323..d106b00293 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php @@ -72,7 +72,7 @@ class Delete extends Action public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php index 91fa3582f7..8528d6d2cd 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php @@ -73,7 +73,7 @@ class Get extends Action public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php index 75471b826c..3a451d3839 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php @@ -90,7 +90,7 @@ class Create extends Action $key ??= $relatedCollectionId; $twoWayKey ??= $collectionId; - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php index 6daa180df9..60e05420a4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php @@ -67,7 +67,7 @@ class XList extends Action public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php index b810ce602f..9b71c80337 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php @@ -82,7 +82,7 @@ class Create extends Action public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php index d124a47289..e1c4122942 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php @@ -69,7 +69,7 @@ class Delete extends Action public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index 3da89f352c..cda3f0371f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -297,7 +297,7 @@ abstract class Action extends AppwriteAction $relatedCollectionId = $relationship->getAttribute('relatedCollection'); if (!isset($collectionsCache[$relatedCollectionId])) { - $relatedCollectionDoc = Authorization::skip( + $relatedCollectionDoc = $dbForProject->getAuthorization()->skip( fn () => $dbForProject->getDocument( 'database_' . $database->getSequence(), $relatedCollectionId diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php index 0b3d0e9fb4..4e41784b59 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php @@ -89,15 +89,15 @@ class Decrement extends Action public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan): void { - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception($this->getParentNotFoundException()); } @@ -105,7 +105,7 @@ class Decrement extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php index ef64099fa8..3b47a3f14c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php @@ -89,15 +89,15 @@ class Increment extends Action public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan): void { - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception($this->getParentNotFoundException()); } @@ -105,7 +105,7 @@ class Increment extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index 521190d3dc..d53bf44922 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -23,7 +23,7 @@ use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -177,19 +177,19 @@ class Create extends Action $documents = [$data]; } - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($isBulk && !$isAPIKey && !$isPrivilegedUser) { throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE); } - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -246,8 +246,8 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', Authorization::getRoles()) . ')'); + if (!$dbForProject->getAuthorization()->hasRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $dbForProject->getAuthorization()->getRoles()) . ')'); } } } @@ -262,17 +262,17 @@ class Create extends Action $operations++; $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization($permission); - $valid = $validator->isValid($collection->getPermissionsByType($permission)); - if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + $validCollection = $dbForProject->getAuthorization()->isValid(new Input($permission, $collection->getPermissionsByType($permission))); + if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$validCollection) { + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($permission === Database::PERMISSION_UPDATE) { - $valid = $valid || $validator->isValid($document->getUpdate()); + $validDocument= $dbForProject->getAuthorization()->isValid(new Input($permission, $document->getUpdate())); + $valid = $validCollection || $validDocument; if ($documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } } @@ -297,7 +297,7 @@ class Create extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip( + $relatedCollection = $dbForProject->getAuthorization()->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -313,7 +313,7 @@ class Create extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $current = Authorization::skip( + $current = $dbForProject->getAuthorization()->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId()) ); @@ -368,7 +368,7 @@ class Create extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -503,4 +503,4 @@ class Create extends Action $this->getResponseModel() ); } -} +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index a4cef59e5f..e213687b54 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -98,16 +98,16 @@ class Delete extends Action TransactionState $transactionState, array $plan ): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -120,7 +120,7 @@ class Delete extends Action // Use transaction-aware document retrieval to see changes from same transaction $document = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $document = Authorization::skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $document = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($document->isEmpty()) { @@ -130,7 +130,7 @@ class Delete extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php index 3d8cd9198c..43dee6083d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php @@ -74,15 +74,15 @@ class Get extends Action public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState): void { - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php index 241b0c4ede..a4ac205a2d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php @@ -78,7 +78,7 @@ class XList extends Action public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index 552c51a5fb..faf7b7db3b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -97,16 +97,16 @@ class Update extends Action throw new Exception($this->getMissingPayloadException()); } - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -120,7 +120,7 @@ class Update extends Action // Use transaction-aware document retrieval to see changes from same transaction $document = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $document = Authorization::skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $document = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($document->isEmpty()) { @@ -135,7 +135,7 @@ class Update extends Action ]); // Users can only manage their own roles, API keys and Admin users can manage any - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -148,7 +148,7 @@ class Update extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { + if (!$dbForProject->getAuthorization()->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -190,7 +190,7 @@ class Update extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip( + $relatedCollection = $dbForProject->getAuthorization()->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -207,7 +207,7 @@ class Update extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( + $oldDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId() )); @@ -245,7 +245,7 @@ class Update extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index f113a99c7a..50e4e840fc 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -105,15 +105,15 @@ class Upsert extends Action throw new Exception($this->getMissingPayloadException()); } - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -134,7 +134,7 @@ class Upsert extends Action // Use transaction-aware document retrieval to see changes from same transaction $oldDocument = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $oldDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($oldDocument->isEmpty()) { if (!empty($user->getId())) { @@ -150,7 +150,7 @@ class Upsert extends Action } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -163,7 +163,7 @@ class Upsert extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { + if (!$dbForProject->getAuthorization()->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -200,7 +200,7 @@ class Upsert extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip( + $relatedCollection = $dbForProject->getAuthorization()->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -217,7 +217,7 @@ class Upsert extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( + $oldDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId() )); @@ -254,7 +254,7 @@ class Upsert extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index a30fed47ed..26866ac33d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -76,15 +76,15 @@ class XList extends Action public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState): void { - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -112,7 +112,7 @@ class XList extends Action $documentId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId)); + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId)); if ($cursorDocument->isEmpty()) { $type = ucfirst($this->getContext()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php index 89739570c7..18509da214 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php @@ -62,7 +62,7 @@ class Get extends Action public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php index 9fb438d577..c3e7e66b2e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php @@ -84,7 +84,7 @@ class Create extends Action public function action(string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php index 2bccfdfb52..dbe6e48dd3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php @@ -75,7 +75,7 @@ class Delete extends Action public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php index 3d118d1922..e703ad03b3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php @@ -64,7 +64,7 @@ class Get extends Action public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php index 60e52f883a..f8ee258698 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php @@ -70,7 +70,7 @@ class XList extends Action public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject): void { /** @var Document $database */ - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -110,7 +110,7 @@ class XList extends Action } $indexId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ + $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionInternalId', [$collection->getSequence()]), Query::equal('databaseInternalId', [$database->getSequence()]), Query::equal('key', [$indexId]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php index b202120bad..f6046cc468 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php @@ -77,7 +77,7 @@ class XList extends Action public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php index 49870002ce..42fdbfb7f1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php @@ -75,7 +75,7 @@ class Update extends Action public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php index 9cf7b85267..3ec9dafe5c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php @@ -83,7 +83,7 @@ class Get extends Action str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getSequence(), $collectionDocument->getSequence()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php index b4cc5470d9..59d0540224 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php @@ -70,7 +70,7 @@ class XList extends Action public function action(string $databaseId, array $queries, string $search, UtopiaResponse $response, Database $dbForProject): void { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php index c4c5bf8b51..ebe06661f5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php @@ -73,7 +73,7 @@ class Create extends Action } } - $transaction = Authorization::skip(fn () => $dbForProject->createDocument('transactions', new Document([ + $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('transactions', new Document([ '$id' => ID::unique(), '$permissions' => $permissions, 'status' => 'pending', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index bd94c1c7eb..66f86045fe 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -17,7 +17,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; @@ -72,12 +72,12 @@ class Create extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Operations array cannot be empty'); } - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); // API keys and admins can read any transaction, regular users need permissions $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -113,13 +113,13 @@ class Create extends Action throw new Exception(Exception::USER_UNAUTHORIZED); } - $database = $databases[$operation['databaseId']] ??= Authorization::skip(fn () => $dbForProject->getDocument('databases', $operation['databaseId'])); + $database = $databases[$operation['databaseId']] ??= $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $operation['databaseId'])); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = $collections[$operation[$this->getGroupId()]] ??= - Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $operation[$this->getGroupId()])); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $operation[$this->getGroupId()])); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -165,8 +165,10 @@ class Create extends Action // For individual operations, enforce permissions unless using API key/admin if (!$isAPIKey && !$isPrivilegedUser) { $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization($permissionType); - $collectionValid = $validator->isValid($collection->getPermissionsByType($permissionType)); + + $collectionValid = $dbForProject->getAuthorization()->isValid( + new input($permissionType, $collection->getPermissionsByType($permissionType)) + ); $documentValid = false; if ($document !== null && !$document->isEmpty() && $documentSecurity) { if ($permissionType === Database::PERMISSION_UPDATE) { @@ -189,7 +191,7 @@ class Create extends Action // Users can only set permissions for roles they have if (isset($operation['data']['$permissions'])) { $permissions = $operation['data']['$permissions']; - $roles = Authorization::getRoles(); + $roles = $dbForProject->getAuthorization()->getRoles(); foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -201,7 +203,7 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { + if (!$dbForProject->getAuthorization()->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -230,7 +232,7 @@ class Create extends Action } } - $transaction = Authorization::skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { + $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { $dbForProject->createDocuments('transactionLogs', $staged); return $dbForProject->increaseDocumentAttribute( 'transactions', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index 6e2bd63827..ec43cfa87f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -111,11 +111,11 @@ class Update extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Cannot commit and rollback at the same time'); } - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); $transaction = ($isAPIKey || $isPrivilegedUser) - ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -138,11 +138,11 @@ class Update extends Action try { $dbForProject->withTransaction(function () use ($dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, $queueForEvents, $queueForStatsUsage, $queueForRealtime, $queueForFunctions, $queueForWebhooks) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'committing', ]))); - $operations = Authorization::skip(fn () => $dbForProject->find('transactionLogs', [ + $operations = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX), @@ -218,7 +218,7 @@ class Update extends Action } } - $transaction = Authorization::skip(fn () => $dbForProject->updateDocument( + $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument( 'transactions', $transactionId, new Document(['status' => 'committed']) @@ -230,32 +230,32 @@ class Update extends Action }); } catch (NotFoundException $e) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::DOCUMENT_NOT_FOUND, previous: $e); } catch (DuplicateException|ConflictException $e) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::TRANSACTION_CONFLICT, previous: $e); } catch (StructureException $e) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage()); } catch (LimitException $e) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, $e->getMessage()); } catch (TransactionException $e) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::TRANSACTION_FAILED, $e->getMessage()); } catch (QueryException $e) { - Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); @@ -283,11 +283,11 @@ class Update extends Action $data = $data->getArrayCopy(); } - $database = Authorization::skip(fn () => $dbForProject->findOne('databases', [ + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('databases', [ Query::equal('$sequence', [$databaseInternalId]) ])); - $collection = Authorization::skip(fn () => $dbForProject->findOne('database_' . $databaseInternalId, [ + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('database_' . $databaseInternalId, [ Query::equal('$sequence', [$collectionInternalId]) ])); @@ -379,7 +379,7 @@ class Update extends Action } if ($rollback) { - $transaction = Authorization::skip(fn () => $dbForProject->updateDocument( + $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument( 'transactions', $transactionId, new Document(['status' => 'failed']) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php index c9de9d5217..112892d39d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php @@ -81,7 +81,7 @@ class Get extends Action str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES) ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php index c13149cfc7..4c0515c02b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php @@ -74,7 +74,7 @@ class XList extends Action METRIC_DATABASES_OPERATIONS_WRITES, ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index 69af3b7d04..a05dfbd2a4 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -26,7 +26,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; @@ -152,10 +152,10 @@ class Create extends Base throw new Exception($validator->getDescription(), 400); } - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRole); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); @@ -171,7 +171,7 @@ class Create extends Base throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } - $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''))); + $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''))); if ($deployment->getAttribute('resourceId') !== $function->getId()) { throw new Exception(Exception::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function'); @@ -185,10 +185,8 @@ class Create extends Base throw new Exception(Exception::BUILD_NOT_READY); } - $validator = new Authorization('execute'); - - if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function - throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); + if (!$dbForProject->getAuthorization()->isValid(new Input('execute', $function->getAttribute('execute')))) { // Check if user has write access to execute function + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } $jwt = ''; // initialize @@ -286,7 +284,7 @@ class Create extends Base if ($async) { if (is_null($scheduledAt)) { - $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('executions', $execution)); $queueForFunctions ->setType('http') ->setExecution($execution) @@ -327,7 +325,7 @@ class Create extends Base ->setAttribute('scheduleInternalId', $schedule->getSequence()) ->setAttribute('scheduledAt', $scheduledAt); - $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('executions', $execution)); } return $response @@ -480,7 +478,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))) ; - $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('executions', $execution)); } $executionResponse['headers']['x-appwrite-execution-id'] = $execution->getId(); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php index 666cb8310c..fbe53218d3 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php @@ -108,7 +108,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('active', false); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php index 42d78f8ca8..e0f90e5f00 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php @@ -61,10 +61,10 @@ class Get extends Base Response $response, Database $dbForProject ) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php index 46a41e6517..b4fe89e5ce 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php @@ -67,10 +67,10 @@ class XList extends Base Response $response, Database $dbForProject ) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index 932f515fc1..0f137a42c0 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -237,7 +237,7 @@ class Create extends Base throw new Exception(Exception::FUNCTION_ALREADY_EXISTS); } - $schedule = Authorization::skip( + $schedule = $dbForProject->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('schedules', new Document([ 'region' => $project->getAttribute('region'), 'resourceType' => SCHEDULE_RESOURCE_TYPE_FUNCTION, @@ -365,7 +365,7 @@ class Create extends Base // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $rule = Authorization::skip( + $rule = $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php index 72d5589252..8462e649a2 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php @@ -87,7 +87,7 @@ class Delete extends Base $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('active', false); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queueForDeletes ->setType(DELETE_TYPE_DOCUMENT) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index 8846329d27..7d521caa9c 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -101,7 +101,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queries = [ Query::equal('trigger', ['manual']), @@ -112,12 +112,12 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - Authorization::skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); - Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }, $queries)); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php index aaff953af0..cce896713c 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php @@ -282,7 +282,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queueForEvents->setParam('functionId', $function->getId()); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php index acb6995d6f..c2ea423c31 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php @@ -83,7 +83,7 @@ class Get extends Base str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_FAILED), ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php index 6a4ded4db7..877e014dfb 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php @@ -75,7 +75,7 @@ class XList extends Base str_replace("{resourceType}", RESOURCE_TYPE_FUNCTIONS, METRIC_RESOURCE_TYPE_BUILDS_FAILED), ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php index 815d364dad..4c1141e1a7 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php @@ -119,7 +119,7 @@ class Create extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response ->setStatusCode(Response::STATUS_CODE_CREATED) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php index 35f9618edb..bc85063a26 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php @@ -92,7 +92,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->noContent(); } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php index 639b1c74d5..b571a63709 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php @@ -109,7 +109,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->dynamic($variable, Response::MODEL_VARIABLE); } diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index d6385c1f40..cff0073523 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -916,7 +916,7 @@ class Builds extends Action ->trigger(); try { - $rule = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ + $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal("projectInternalId", [$project->getSequence()]), Query::equal("type", ["deployment"]), Query::equal('deploymentInternalId', [$deployment->getSequence()]), @@ -930,7 +930,7 @@ class Builds extends Action $client->setTimeout(\intval($resource->getAttribute('timeout', '15'))); $client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON); - $bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); $configs = [ 'screenshotLight' => [ @@ -1052,7 +1052,7 @@ class Builds extends Action 'metadata' => ['content_type' => $mimeType], ]); - Authorization::skip(fn () => $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file)); $deployment->setAttribute($key, $fileId); } @@ -1275,7 +1275,7 @@ class Builds extends Action ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $resource->getAttribute('schedule')) ->setAttribute('active', !empty($resource->getAttribute('schedule')) && !empty($resource->getAttribute('deploymentId'))); - Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); } Console::info('Deployment action finished'); @@ -1570,7 +1570,7 @@ class Builds extends Action default => throw new \Exception('Invalid resource type') }; - $rule = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ + $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal("projectInternalId", [$project->getSequence()]), Query::equal("type", ["deployment"]), Query::equal("deploymentInternalId", [$deployment->getSequence()]), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index 65a0fcf143..5f7e442bdd 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -274,7 +274,7 @@ class Create extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - Authorization::skip( + $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -339,7 +339,7 @@ class Create extends Action $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); $domain = ID::unique() . "." . $sitesDomain; $ruleId = md5($domain); - Authorization::skip( + $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php index 065dd13e88..721d55bdf1 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php @@ -146,7 +146,7 @@ class Create extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - Authorization::skip( + $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index dc90045b0c..f7dc9a3c43 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -176,7 +176,7 @@ class Create extends Base // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - Authorization::skip( + $dbForPlatform->getAuthorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index bb6bd4f632..7abfb02689 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -104,12 +104,12 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - Authorization::skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); - Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }, $queries)); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php index af96c10457..3864a6328f 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php @@ -91,7 +91,7 @@ class Get extends Base ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php index d36cc56ae5..eec1b321c6 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php @@ -78,7 +78,7 @@ class XList extends Base METRIC_SITES_OUTBOUND, ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php index 5708f1b83b..17984a1725 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php @@ -5,33 +5,31 @@ namespace Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files; use Appwrite\Auth\Auth; use Appwrite\Extend\Exception; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Platform\Action as UtopiaAction; class Action extends UtopiaAction { protected function getFileAndBucket(Database $dbForProject, string $bucketId, string $fileId): array { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($bucket->getRead()); - if (!$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()))){ + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); if ($fileSecurity) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($file->isEmpty()) { diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index fe7a0187e9..57bf7cf1a9 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -13,7 +13,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; @@ -78,11 +78,10 @@ class Create extends Action ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $validator = new Authorization(Database::PERMISSION_UPDATE); - $bucketPermission = $validator->isValid($bucket->getUpdate()); - + $bucketPermission = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); + if ($fileSecurity) { - $filePermission = $validator->isValid($file->getUpdate()); + $filePermission = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $file->getUpdate())); if (!$bucketPermission && !$filePermission) { throw new Exception(Exception::USER_UNAUTHORIZED); } diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 3e35c1c1fa..721a1f4039 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -48,7 +48,7 @@ class Migrate extends Action callable $getProjectDB, Registry $register, ): void { - Authorization::disable(); + $dbForPlatform->getAuthorization()->disable(); if (!\array_key_exists($version, Migration::$versions)) { Console::error("No migration found for version $version."); diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index e9a0e1d333..f696dbd790 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -62,7 +62,7 @@ abstract class ScheduleBase extends Action $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } } } diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index b64dd61f86..102a25df62 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -61,9 +61,9 @@ class StatsResources extends Action $interval = (int) System::getEnv('_APP_STATS_RESOURCES_INTERVAL', '3600'); - Console::loop(function () use ($queue) { - Authorization::disable(); - Authorization::setDefaultStatus(false); + Console::loop(function () use ($queue, $dbForPlatform) { + $dbForPlatform->getAuthorization()->disable(); + $dbForPlatform->getAuthorization()->setDefaultStatus(false); $last24Hours = (new \DateTime())->sub(\DateInterval::createFromDateString('24 hours')); /** diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 331a2668a3..8769e2f56b 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -954,14 +954,14 @@ class Deletes extends Action } Console::info("Deleting screenshots for deployment " . $deployment->getId()); - $bucket = ValidatorAuthorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); if ($bucket->isEmpty()) { Console::error('Failed to get bucket for deployment screenshots'); return; } foreach ($screenshotIds as $id) { - $file = ValidatorAuthorization::skip(fn () => $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $id)); + $file = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $id)); if ($file->isEmpty()) { Console::error('Failed to get deployment screenshot: ' . $id); diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 558f0cdf09..75f0744098 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -210,7 +210,7 @@ class Request extends UtopiaRequest { $forwardedUserAgent = $this->getHeader('x-forwarded-user-agent'); if (!empty($forwardedUserAgent)) { - $roles = Authorization::getRoles(); + $roles = $this->authorization->getRoles(); $isAppUser = Auth::isAppUser($roles); if ($isAppUser) { @@ -233,4 +233,11 @@ class Request extends UtopiaRequest ksort($params); return md5($this->getURI() . '*' . serialize($params) . '*' . APP_CACHE_BUSTER); } + + private Authorization $authorization; + + public function setAuthorization(Authorization $authorization): void + { + $this->authorization = $authorization; + } } diff --git a/src/Appwrite/Utopia/Request/Filters/V20.php b/src/Appwrite/Utopia/Request/Filters/V20.php index 3783a61947..8f500c9380 100644 --- a/src/Appwrite/Utopia/Request/Filters/V20.php +++ b/src/Appwrite/Utopia/Request/Filters/V20.php @@ -139,7 +139,7 @@ class V20 extends Filter } try { - $database = Authorization::skip(fn () => $dbForProject->getDocument( + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( 'databases', $databaseId )); @@ -151,7 +151,7 @@ class V20 extends Filter } try { - $collection = Authorization::skip(fn () => $dbForProject->getDocument( + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence(), $collectionId )); diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index b391f0ea72..099bf7fd44 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -809,7 +809,7 @@ class Response extends SwooleResponse } if ($rule['sensitive']) { - $roles = Authorization::getRoles(); + $roles = $this->authorization->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -977,4 +977,11 @@ class Response extends SwooleResponse self::$showSensitive = false; } } + + private Authorization $authorization; + + public function setAuthorization(Authorization $authorization): void + { + $this->authorization = $authorization; + } } diff --git a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php index 6496aa285a..26e11ff0b9 100644 --- a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php @@ -17,6 +17,16 @@ class DatabasesPermissionsGuestTest extends Scope use SideClient; use DatabasesPermissionsScope; +private $authorization; + +public function getAuthorization(): Authorization +{ + if (isset($this->authorization)) { + return $this->authorization; + } + return new Authorization(); +} + public function createCollection(): array { $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ @@ -111,8 +121,8 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(201, $publicResponse['headers']['status-code']); $this->assertEquals(201, $privateResponse['headers']['status-code']); - $roles = Authorization::getRoles(); - Authorization::cleanRoles(); + $roles = $this->getAuthorization()->getRoles(); + $this->getAuthorization()->cleanRoles(); $publicDocuments = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ 'content-type' => 'application/json', @@ -134,7 +144,7 @@ class DatabasesPermissionsGuestTest extends Scope } foreach ($roles as $role) { - Authorization::setRole($role); + $this->getAuthorization()->addRole($role); } } @@ -145,8 +155,8 @@ class DatabasesPermissionsGuestTest extends Scope $privateCollectionId = $data['privateCollectionId']; $databaseId = $data['databaseId']; - $roles = Authorization::getRoles(); - Authorization::cleanRoles(); + $roles = $this->getAuthorization()->getRoles(); + $this->getAuthorization()->cleanRoles(); $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ 'content-type' => 'application/json', @@ -222,7 +232,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateDocument['headers']['status-code']); foreach ($roles as $role) { - Authorization::setRole($role); + $this->getAuthorization()->addRole($role); } } diff --git a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php index 2f69c037d0..20a91c6717 100644 --- a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php @@ -17,6 +17,17 @@ class DatabasesPermissionsGuestTest extends Scope use SideClient; use DatabasesPermissionsScope; + private $authorization; + + public function getAuthorization(): Authorization + { + if (isset($this->authorization)) { + return $this->authorization; + } + return new Authorization(); + } + + public function createTable(): array { $database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([ @@ -111,8 +122,8 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(201, $publicResponse['headers']['status-code']); $this->assertEquals(201, $privateResponse['headers']['status-code']); - $roles = Authorization::getRoles(); - Authorization::cleanRoles(); + $roles = $this->getAuthorization()->getRoles(); + $this->getAuthorization()->cleanRoles(); $publicRows = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $publicTableId . '/rows', [ 'content-type' => 'application/json', @@ -134,7 +145,7 @@ class DatabasesPermissionsGuestTest extends Scope } foreach ($roles as $role) { - Authorization::setRole($role); + $this->getAuthorization()->addRole($role); } } @@ -145,8 +156,8 @@ class DatabasesPermissionsGuestTest extends Scope $privateTableId = $data['privateTableId']; $databaseId = $data['databaseId']; - $roles = Authorization::getRoles(); - Authorization::cleanRoles(); + $roles = $this->getAuthorization()->getRoles(); + $this->getAuthorization()->cleanRoles(); $publicResponse = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $publicTableId . '/rows', [ 'content-type' => 'application/json', @@ -222,7 +233,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateRow['headers']['status-code']); foreach ($roles as $role) { - Authorization::setRole($role); + $this->getAuthorization()->addRole($role); } } diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 705da42879..4fef733457 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -13,13 +13,24 @@ use Utopia\Database\Validator\Roles; class AuthTest extends TestCase { + private $authorization; + + public function getAuthorization(): Authorization + { + if (isset($this->authorization)) { + return $this->authorization; + } + return new Authorization(); + } + + /** * Reset Roles */ public function tearDown(): void { - Authorization::cleanRoles(); - Authorization::setRole(Role::any()->toString()); + $this->getAuthorization()->cleanRoles(); + $this->getAuthorization()->addRole(Role::any()->toString()); } public function testCookieName(): void @@ -347,7 +358,7 @@ class AuthTest extends TestCase '$id' => '' ]); - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, new Authorization()); $this->assertCount(1, $roles); $this->assertContains(Role::guests()->toString(), $roles); } @@ -383,7 +394,7 @@ class AuthTest extends TestCase ] ]); - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $this->assertCount(13, $roles); $this->assertContains(Role::users()->toString(), $roles); @@ -404,21 +415,21 @@ class AuthTest extends TestCase $user['emailVerification'] = false; $user['phoneVerification'] = false; - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $this->assertContains(Role::users(Roles::DIMENSION_UNVERIFIED)->toString(), $roles); $this->assertContains(Role::user(ID::custom('123'), Roles::DIMENSION_UNVERIFIED)->toString(), $roles); // Enable single verification type $user['emailVerification'] = true; - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $this->assertContains(Role::users(Roles::DIMENSION_VERIFIED)->toString(), $roles); $this->assertContains(Role::user(ID::custom('123'), Roles::DIMENSION_VERIFIED)->toString(), $roles); } public function testPrivilegedUserRoles(): void { - Authorization::setRole(Auth::USER_ROLE_OWNER); + $this->getAuthorization()->addRole(Auth::USER_ROLE_OWNER); $user = new Document([ '$id' => ID::custom('123'), 'emailVerification' => true, @@ -444,7 +455,7 @@ class AuthTest extends TestCase ] ]); - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $this->assertCount(7, $roles); $this->assertNotContains(Role::users()->toString(), $roles); @@ -462,7 +473,7 @@ class AuthTest extends TestCase public function testAppUserRoles(): void { - Authorization::setRole(Auth::USER_ROLE_APPS); + $this->getAuthorization()->addRole(Auth::USER_ROLE_APPS); $user = new Document([ '$id' => ID::custom('123'), 'memberships' => [ @@ -486,7 +497,7 @@ class AuthTest extends TestCase ] ]); - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $this->assertCount(7, $roles); $this->assertNotContains(Role::users()->toString(), $roles); diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index 8ba0374093..54784edada 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -8,6 +8,7 @@ use PHPUnit\Framework\TestCase; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; class MessagingChannelsTest extends TestCase { @@ -34,6 +35,16 @@ class MessagingChannelsTest extends TestCase 'functions.1', ]; + private $authorization; + + public function getAuthorization(): Authorization + { + if (isset($this->authorization)) { + return $this->authorization; + } + return new Authorization(); + } + public function setUp(): void { /** @@ -66,7 +77,7 @@ class MessagingChannelsTest extends TestCase ] ]); - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $parsedChannels = Realtime::convertChannels([0 => $channel], $user->getId()); @@ -90,7 +101,7 @@ class MessagingChannelsTest extends TestCase '$id' => '' ]); - $roles = Auth::getRoles($user); + $roles = Auth::getRoles($user, $this->getAuthorization()); $parsedChannels = Realtime::convertChannels([0 => $channel], $user->getId()); From 8b3b07a710e328d670dce67391475b2b7fda698e Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 22 Oct 2025 16:40:00 +0300 Subject: [PATCH 016/167] linter --- app/controllers/api/account.php | 3 +-- app/controllers/api/avatars.php | 1 - app/controllers/api/migrations.php | 1 - app/controllers/api/project.php | 1 - app/controllers/api/storage.php | 2 +- app/controllers/api/teams.php | 1 - app/controllers/api/users.php | 1 - app/controllers/api/vcs.php | 1 - app/controllers/shared/api.php | 2 +- app/http.php | 1 - app/init/database/filters.php | 1 - src/Appwrite/Databases/TransactionState.php | 3 +-- src/Appwrite/Migration/Migration.php | 1 - src/Appwrite/Platform/Modules/Compute/Base.php | 1 - .../Modules/Console/Http/Resources/Get.php | 1 - .../Databases/Collections/Attributes/Action.php | 1 - .../Databases/Collections/Attributes/Delete.php | 1 - .../Http/Databases/Collections/Attributes/Get.php | 1 - .../Collections/Attributes/Relationship/Create.php | 1 - .../Databases/Collections/Attributes/XList.php | 1 - .../Http/Databases/Collections/Create.php | 1 - .../Http/Databases/Collections/Delete.php | 1 - .../Databases/Collections/Documents/Action.php | 1 - .../Collections/Documents/Attribute/Decrement.php | 1 - .../Collections/Documents/Attribute/Increment.php | 1 - .../Databases/Collections/Documents/Create.php | 4 ++-- .../Databases/Collections/Documents/Delete.php | 1 - .../Http/Databases/Collections/Documents/Get.php | 1 - .../Databases/Collections/Documents/Logs/XList.php | 1 - .../Databases/Collections/Documents/Update.php | 1 - .../Databases/Collections/Documents/Upsert.php | 1 - .../Http/Databases/Collections/Documents/XList.php | 1 - .../Databases/Http/Databases/Collections/Get.php | 1 - .../Http/Databases/Collections/Indexes/Create.php | 1 - .../Http/Databases/Collections/Indexes/Delete.php | 1 - .../Http/Databases/Collections/Indexes/Get.php | 1 - .../Http/Databases/Collections/Indexes/XList.php | 1 - .../Http/Databases/Collections/Logs/XList.php | 1 - .../Http/Databases/Collections/Update.php | 1 - .../Http/Databases/Collections/Usage/Get.php | 1 - .../Databases/Http/Databases/Collections/XList.php | 1 - .../Http/Databases/Transactions/Create.php | 1 - .../Databases/Transactions/Operations/Create.php | 2 +- .../Modules/Databases/Http/Databases/Usage/Get.php | 1 - .../Databases/Http/Databases/Usage/XList.php | 1 - .../Modules/Functions/Http/Executions/Delete.php | 1 - .../Modules/Functions/Http/Executions/Get.php | 1 - .../Modules/Functions/Http/Executions/XList.php | 1 - .../Modules/Functions/Http/Functions/Create.php | 1 - .../Modules/Functions/Http/Functions/Delete.php | 1 - .../Functions/Http/Functions/Deployment/Update.php | 1 - .../Modules/Functions/Http/Functions/Update.php | 1 - .../Platform/Modules/Functions/Http/Usage/Get.php | 1 - .../Modules/Functions/Http/Usage/XList.php | 1 - .../Modules/Functions/Http/Variables/Create.php | 1 - .../Modules/Functions/Http/Variables/Delete.php | 1 - .../Modules/Functions/Http/Variables/Update.php | 1 - .../Modules/Sites/Http/Deployments/Create.php | 1 - .../Sites/Http/Deployments/Duplicate/Create.php | 1 - .../Sites/Http/Deployments/Template/Create.php | 1 - .../Modules/Sites/Http/Sites/Deployment/Update.php | 1 - .../Platform/Modules/Sites/Http/Usage/Get.php | 1 - .../Platform/Modules/Sites/Http/Usage/XList.php | 1 - .../Tokens/Http/Tokens/Buckets/Files/Action.php | 2 +- .../Tokens/Http/Tokens/Buckets/Files/Create.php | 2 +- src/Appwrite/Platform/Tasks/Migrate.php | 1 - src/Appwrite/Platform/Tasks/ScheduleBase.php | 1 - src/Appwrite/Platform/Tasks/StatsResources.php | 1 - src/Appwrite/Platform/Workers/Deletes.php | 1 - src/Appwrite/Utopia/Request.php | 2 +- src/Appwrite/Utopia/Request/Filters/V20.php | 1 - src/Appwrite/Utopia/Response.php | 2 +- .../Permissions/DatabasesPermissionsGuestTest.php | 14 +++++++------- 73 files changed, 18 insertions(+), 82 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index aeeff76dff..8dfe4b51b7 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -51,7 +51,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; @@ -228,7 +227,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res Permission::delete(Role::user($user->getId())), ])); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); + $dbForProject->getAuthorization()->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); $dbForProject->purgeCachedDocument('users', $user->getId()); // Magic URL + Email OTP diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 64f13c1981..4952a763fc 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -16,7 +16,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Domains\Domain; use Utopia\Fetch\Client; diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 4f88adf616..f370580a79 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -19,7 +19,6 @@ use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Migration\Resource; diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 554d2defec..061711c96a 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -14,7 +14,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DateTimeValidator; use Utopia\Database\Validator\UID; use Utopia\Validator\Boolean; diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index ebccc9c321..ab003bedf1 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -739,7 +739,7 @@ App::post('/v1/storage/buckets/:bucketId/files') if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } - + try { $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } catch (NotFoundException) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index eb70282ff4..5843cebeca 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -41,7 +41,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 9c7cd75817..d7b4b56806 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -43,7 +43,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 564f6e5493..354c89999b 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -27,7 +27,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Detector\Detection\Framework\Astro; use Utopia\Detector\Detection\Framework\Flutter; diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 113b665925..f9109c3be3 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -328,7 +328,7 @@ App::init() $scopes = \array_unique($scopes); $dbForPlatform->getAuthorization()->addRole($role); - foreach (Auth::getRoles($user, $dbForPlatform->getAuthorization()) as $authRole) { + foreach (Auth::getRoles($user, $dbForPlatform->getAuthorization()) as $authRole) { $dbForPlatform->getAuthorization()->addRole($authRole); } diff --git a/app/http.php b/app/http.php index 0f65bb6606..629d1d21b7 100644 --- a/app/http.php +++ b/app/http.php @@ -25,7 +25,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Logger\Log; use Utopia\Logger\Log\User; use Utopia\Pools\Group; diff --git a/app/init/database/filters.php b/app/init/database/filters.php index 1e2f458724..c065bf0d82 100644 --- a/app/init/database/filters.php +++ b/app/init/database/filters.php @@ -4,7 +4,6 @@ use Appwrite\OpenSSL\OpenSSL; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\System\System; Database::addFilter( diff --git a/src/Appwrite/Databases/TransactionState.php b/src/Appwrite/Databases/TransactionState.php index 123e2f767f..44ba62c4a4 100644 --- a/src/Appwrite/Databases/TransactionState.php +++ b/src/Appwrite/Databases/TransactionState.php @@ -7,7 +7,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception; use Utopia\Database\Exception\Timeout; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; /** * Service for managing transaction state and providing transaction-aware document operations @@ -347,7 +346,7 @@ class TransactionState return []; } - $operations =$this->dbForProject->getAuthorization()->skip(fn () => $this->dbForProject->find('transactionLogs', [ + $operations = $this->dbForProject->getAuthorization()->skip(fn () => $this->dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX) diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index f338b2ab29..142c828ac5 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -13,7 +13,6 @@ use Utopia\Database\Exception\Limit; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; use Utopia\Database\PDO; -use Utopia\Database\Validator\Authorization; abstract class Migration { diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 168ee7fc79..f90d615cac 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -11,7 +11,6 @@ use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\VCS\Adapter\Git\GitHub; diff --git a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php index 3bb49e7142..2abe4e0957 100644 --- a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php +++ b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php @@ -10,7 +10,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Domains\Domain as Domain; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php index 9e014fd083..5b41c42200 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php @@ -17,7 +17,6 @@ use Utopia\Database\Exception\Relationship as RelationshipException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Exception\Truncate as TruncateException; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Structure; use Utopia\Platform\Action as UtopiaAction; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php index d106b00293..ec8005993c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\IndexDependency as IndexDependencyValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php index 8528d6d2cd..158184e336 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php @@ -9,7 +9,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php index 3a451d3839..a502c2012b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php @@ -13,7 +13,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php index 60e05420a4..e632f6397e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php @@ -14,7 +14,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php index 9b71c80337..8a9088382d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php @@ -19,7 +19,6 @@ use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php index e1c4122942..a9eebbc9d6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index cda3f0371f..bbf62b2e83 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -7,7 +7,6 @@ use Appwrite\Extend\Exception; use Appwrite\Platform\Action as AppwriteAction; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; abstract class Action extends AppwriteAction { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php index 4e41784b59..9f92a707f8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php @@ -21,7 +21,6 @@ use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Type as TypeException; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php index 3b47a3f14c..b97a937e58 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php @@ -21,7 +21,6 @@ use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Type as TypeException; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index d53bf44922..5a5e3f223b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -269,7 +269,7 @@ class Create extends Action } if ($permission === Database::PERMISSION_UPDATE) { - $validDocument= $dbForProject->getAuthorization()->isValid(new Input($permission, $document->getUpdate())); + $validDocument = $dbForProject->getAuthorization()->isValid(new Input($permission, $document->getUpdate())); $valid = $validCollection || $validDocument; if ($documentSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); @@ -503,4 +503,4 @@ class Create extends Action $this->getResponseModel() ); } -} \ No newline at end of file +} diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index e213687b54..325072f97e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -18,7 +18,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Conflict as ConflictException; use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php index 43dee6083d..93f66ed989 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php @@ -15,7 +15,6 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php index a4ac205a2d..6c38a03ea2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php @@ -18,7 +18,6 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index faf7b7db3b..a969585b6c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -22,7 +22,6 @@ use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 50e4e840fc..6cf2f646eb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -23,7 +23,6 @@ use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index 26866ac33d..dbb30fcc1b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -17,7 +17,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php index 18509da214..9d4183d75f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php @@ -10,7 +10,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php index c3e7e66b2e..7c0d61b588 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php @@ -16,7 +16,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Index as IndexValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php index dbe6e48dd3..cc6ed66466 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php index e703ad03b3..01b186b2c9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php @@ -10,7 +10,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php index f8ee258698..7828b91221 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php @@ -15,7 +15,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php index f6046cc468..a7f24e7c2b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php @@ -18,7 +18,6 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php index 42fdbfb7f1..116b8cdccf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php index 3ec9dafe5c..9ade789cb9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php @@ -14,7 +14,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\WhiteList; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php index 59d0540224..43b4d59255 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php @@ -15,7 +15,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php index ebe06661f5..cd01a03ca4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php @@ -12,7 +12,6 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Validator\Authorization; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Range; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index 66f86045fe..aa3926817e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -165,7 +165,7 @@ class Create extends Action // For individual operations, enforce permissions unless using API key/admin if (!$isAPIKey && !$isPrivilegedUser) { $documentSecurity = $collection->getAttribute('documentSecurity', false); - + $collectionValid = $dbForProject->getAuthorization()->isValid( new input($permissionType, $collection->getPermissionsByType($permissionType)) ); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php index 112892d39d..f75506e5cf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php @@ -13,7 +13,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php index 4c0515c02b..5927f98a02 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php @@ -12,7 +12,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\WhiteList; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php index fbe53218d3..c9dffc82b8 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php @@ -13,7 +13,6 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php index e0f90e5f00..1f11976b8a 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php @@ -10,7 +10,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php index b4fe89e5ce..3cd07b6cea 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php @@ -15,7 +15,6 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index 0f137a42c0..7ca0cb74c8 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -27,7 +27,6 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php index 8462e649a2..5b87031fa0 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php @@ -13,7 +13,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index 7d521caa9c..c1851e3eb3 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -13,7 +13,6 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php index cce896713c..fd19f89afb 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php @@ -22,7 +22,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php index c2ea423c31..501b6bb468 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php @@ -12,7 +12,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php index 877e014dfb..2b8308a75a 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php @@ -11,7 +11,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\WhiteList; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php index 4c1141e1a7..4aedbdabc5 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php @@ -15,7 +15,6 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php index bc85063a26..ecbdf3e13b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php index b571a63709..d83af69a0b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php @@ -11,7 +11,6 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Exception\Duplicate as DuplicateException; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index 5f7e442bdd..9e3812bb1c 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -17,7 +17,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php index 721d55bdf1..4a3b7c804f 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php @@ -12,7 +12,6 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index f7dc9a3c43..5888040476 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -15,7 +15,6 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index 7abfb02689..d89014f7d8 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -12,7 +12,6 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php index 3864a6328f..ca1ef5d9f3 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php @@ -12,7 +12,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php index eec1b321c6..f29ca2bec3 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php @@ -11,7 +11,6 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\WhiteList; diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php index 17984a1725..709a12a957 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php @@ -21,7 +21,7 @@ class Action extends UtopiaAction throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()))){ + if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()))) { throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index 57bf7cf1a9..e0f51308d4 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -79,7 +79,7 @@ class Create extends Action $fileSecurity = $bucket->getAttribute('fileSecurity', false); $bucketPermission = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); - + if ($fileSecurity) { $filePermission = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $file->getUpdate())); if (!$bucketPermission && !$filePermission) { diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 721a1f4039..4bab864653 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -9,7 +9,6 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Exception; -use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Validator\Text; diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index f696dbd790..4e8a5beb76 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -9,7 +9,6 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Queue\Broker\Pool as BrokerPool; use Utopia\System\System; diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index 102a25df62..345c855920 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -8,7 +8,6 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\System\System; /** diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 8769e2f56b..ee0587fad4 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -24,7 +24,6 @@ use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization as ValidatorAuthorization; use Utopia\DSN\DSN; use Utopia\Logger\Log; use Utopia\Platform\Action; diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 75f0744098..a3820f4f1f 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -239,5 +239,5 @@ class Request extends UtopiaRequest public function setAuthorization(Authorization $authorization): void { $this->authorization = $authorization; - } + } } diff --git a/src/Appwrite/Utopia/Request/Filters/V20.php b/src/Appwrite/Utopia/Request/Filters/V20.php index 8f500c9380..0bc1ed4f1f 100644 --- a/src/Appwrite/Utopia/Request/Filters/V20.php +++ b/src/Appwrite/Utopia/Request/Filters/V20.php @@ -8,7 +8,6 @@ use Utopia\Database\Database; use Utopia\Database\Exception\NotFound; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; class V20 extends Filter { diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 099bf7fd44..83ab451c74 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -983,5 +983,5 @@ class Response extends SwooleResponse public function setAuthorization(Authorization $authorization): void { $this->authorization = $authorization; - } + } } diff --git a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php index 26e11ff0b9..60c4421853 100644 --- a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php @@ -17,15 +17,15 @@ class DatabasesPermissionsGuestTest extends Scope use SideClient; use DatabasesPermissionsScope; -private $authorization; + private $authorization; -public function getAuthorization(): Authorization -{ - if (isset($this->authorization)) { - return $this->authorization; + public function getAuthorization(): Authorization + { + if (isset($this->authorization)) { + return $this->authorization; + } + return new Authorization(); } - return new Authorization(); -} public function createCollection(): array { From 25403ea35eff5e48f731c38a3e9344e71b5419c8 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 22 Oct 2025 16:43:49 +0300 Subject: [PATCH 017/167] composer.lock --- composer.lock | 99 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/composer.lock b/composer.lock index 68c88b9c73..4a212ef6f7 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": "f27ea68014d28d445baa355466cdb7a9", + "content-hash": "a2f032a3d278c7f493ea4d87d6908258", "packages": [ { "name": "adhocore/jwt", @@ -3999,21 +3999,22 @@ }, { "name": "utopia-php/domains", - "version": "0.8.4", + "version": "0.9.1", "source": { "type": "git", "url": "https://github.com/utopia-php/domains.git", - "reference": "316a76b0fcbc7f82e40be466c22c19acb243ee22" + "reference": "99b4ec95d5d6b7a5c990a66c56412212d9af37e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/domains/zipball/316a76b0fcbc7f82e40be466c22c19acb243ee22", - "reference": "316a76b0fcbc7f82e40be466c22c19acb243ee22", + "url": "https://api.github.com/repos/utopia-php/domains/zipball/99b4ec95d5d6b7a5c990a66c56412212d9af37e7", + "reference": "99b4ec95d5d6b7a5c990a66c56412212d9af37e7", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/framework": "0.33.*" + "utopia-php/cache": "0.13.*", + "utopia-php/validators": "0.0.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -4054,9 +4055,9 @@ ], "support": { "issues": "https://github.com/utopia-php/domains/issues", - "source": "https://github.com/utopia-php/domains/tree/0.8.4" + "source": "https://github.com/utopia-php/domains/tree/0.9.1" }, - "time": "2025-10-17T11:31:56+00:00" + "time": "2025-10-21T14:52:27+00:00" }, { "name": "utopia-php/dsn", @@ -4394,16 +4395,16 @@ }, { "name": "utopia-php/migration", - "version": "1.3.1", + "version": "1.3.2", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "b6985b235ab64f07a6b88569e20cf9b2df7d838c" + "reference": "f5c1d2cae764290766a4c2d1546c1d51de95b67f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/b6985b235ab64f07a6b88569e20cf9b2df7d838c", - "reference": "b6985b235ab64f07a6b88569e20cf9b2df7d838c", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/f5c1d2cae764290766a4c2d1546c1d51de95b67f", + "reference": "f5c1d2cae764290766a4c2d1546c1d51de95b67f", "shasum": "" }, "require": { @@ -4443,9 +4444,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.3.1" + "source": "https://github.com/utopia-php/migration/tree/1.3.2" }, - "time": "2025-10-21T08:13:54+00:00" + "time": "2025-10-22T12:30:47+00:00" }, { "name": "utopia-php/mongo", @@ -5046,6 +5047,52 @@ }, "time": "2025-03-17T11:57:52+00:00" }, + { + "name": "utopia-php/validators", + "version": "0.0.2", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/validators.git", + "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/validators/zipball/894210695c5d35fa248fb65f7fe7237b6ff4fb0b", + "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-xdebug": "*", + "laravel/pint": "^1.2", + "phpstan/phpstan": "1.*", + "phpunit/phpunit": "^9.5.25" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A lightweight collection of reusable validators for Utopia projects", + "keywords": [ + "php", + "utopia", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/utopia-php/validators/issues", + "source": "https://github.com/utopia-php/validators/tree/0.0.2" + }, + "time": "2025-10-20T21:52:28+00:00" + }, { "name": "utopia-php/vcs", "version": "0.11.0", @@ -5271,16 +5318,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.5", + "version": "1.4.7", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "0c4f514bf861f42555dae781f394fefeb27ff521" + "reference": "a61c8be551e10f4970bf46f75a54e4b0385c550d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/0c4f514bf861f42555dae781f394fefeb27ff521", - "reference": "0c4f514bf861f42555dae781f394fefeb27ff521", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/a61c8be551e10f4970bf46f75a54e4b0385c550d", + "reference": "a61c8be551e10f4970bf46f75a54e4b0385c550d", "shasum": "" }, "require": { @@ -5316,9 +5363,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.4.5" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.7" }, - "time": "2025-10-21T04:59:59+00:00" + "time": "2025-10-22T06:03:44+00:00" }, { "name": "doctrine/annotations", @@ -5795,16 +5842,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { @@ -5847,9 +5894,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { "name": "phar-io/manifest", From c13a70e226e2b9347c0d1e756a6e96e609088974 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 23 Oct 2025 12:38:18 +0300 Subject: [PATCH 018/167] Add users attributes --- app/config/collections/common.php | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/config/collections/common.php b/app/config/collections/common.php index 6de7eb224b..2b3d10e457 100644 --- a/app/config/collections/common.php +++ b/app/config/collections/common.php @@ -364,6 +364,50 @@ return [ 'array' => false, 'filters' => ['datetime'], ], + [ + '$id' => ID::custom('emailIsFree'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('emailIsDisposable'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('emailIsCorporate'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('emailIsCanonical'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ From 6ed2000478300582f5c79b317e666005e059c1a0 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 12:09:23 +0200 Subject: [PATCH 019/167] Update composer.lock and refactor authorization handling in CLI and worker modules. Adjust Docker configuration to include database source path. Modify error handling in general controller and enhance permission setting in document creation. Fix privileged user role retrieval in function execution. Ensure consistent authorization usage across various resources. --- app/cli.php | 10 +++--- app/controllers/general.php | 2 +- app/init/resources.php | 4 ++- app/worker.php | 16 ++++----- composer.lock | 34 +++++++++---------- docker-compose.yml | 1 + .../Collections/Documents/Create.php | 2 +- .../Functions/Http/Executions/Create.php | 2 +- 8 files changed, 35 insertions(+), 36 deletions(-) diff --git a/app/cli.php b/app/cli.php index 08726c2d4d..d30e870c30 100644 --- a/app/cli.php +++ b/app/cli.php @@ -59,6 +59,7 @@ CLI::setResource('pools', function (Registry $register) { CLI::setResource('authorization', function () { $authorization = new Authorization(); + $authorization->disable(); return $authorization; }, []); @@ -133,13 +134,11 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform if (\in_array($dsn->getHost(), $sharedTables)) { $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database - ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -150,18 +149,17 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); + $database->setAuthorization($authorization); $databases[$dsn->getHost()] = $database; $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); if (\in_array($dsn->getHost(), $sharedTables)) { $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database - ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -186,9 +184,9 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio $adapter = new DatabasePool($pools->get('logs')); $database = new Database($adapter, $cache); - + $database->setAuthorization($authorization); + $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK) diff --git a/app/controllers/general.php b/app/controllers/general.php index b6452abd7f..332f0c1d15 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -1175,7 +1175,7 @@ App::error() ->inject('queueForStatsUsage') ->inject('devKey') ->inject('authorization') - ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage, Authorization $authorization) { + ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage, Document $devKey, Authorization $authorization) { $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); $route = $utopia->getRoute(); $class = \get_class($error); diff --git a/app/init/resources.php b/app/init/resources.php index 2d5d8059a6..e85b18d80a 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -424,9 +424,10 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform }, ['pools', 'dbForPlatform', 'cache', 'project', 'authorization']); App::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authorization $authorization) { + $adapter = new DatabasePool($pools->get('console')); $database = new Database($adapter, $cache); - + $database ->setAuthorization($authorization) ->setNamespace('_console') @@ -484,6 +485,7 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); + $database->setAuthorization($authorization); $databases[$dsn->getHost()] = $database; $configure($database); diff --git a/app/worker.php b/app/worker.php index c5dcb14a1e..211b4ebfa6 100644 --- a/app/worker.php +++ b/app/worker.php @@ -51,6 +51,7 @@ Server::setResource('register', fn () => $register); Server::setResource('authorization', function () { $authorization = new Authorization(); + $authorization->disable(); return $authorization; }, []); @@ -58,8 +59,9 @@ Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, $pools = $register->get('pools'); $adapter = new DatabasePool($pools->get('console')); $dbForPlatform = new Database($adapter, $cache); - $dbForPlatform->setNamespace('_console'); $dbForPlatform->setAuthorization($authorization); + $dbForPlatform->setNamespace('_console'); + return $dbForPlatform; }, ['cache', 'register', 'authorization']); @@ -91,18 +93,16 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); - + $database->setAuthorization($authorization); $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); if (\in_array($dsn->getHost(), $sharedTables)) { $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database - ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -130,18 +130,16 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf if (isset($databases[$dsn->getHost()])) { $database = $databases[$dsn->getHost()]; - + $database->setAuthorization($authorization); $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); if (\in_array($dsn->getHost(), $sharedTables)) { $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database - ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); @@ -151,7 +149,9 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf } $adapter = new DatabasePool($pools->get($dsn->getHost())); + $adapter->setAuthorization($authorization); $database = new Database($adapter, $cache); + $database->setAuthorization($authorization); $databases[$dsn->getHost()] = $database; @@ -159,13 +159,11 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf if (\in_array($dsn->getHost(), $sharedTables)) { $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setTenant((int)$project->getSequence()) ->setNamespace($dsn->getParam('namespace')); } else { $database - ->setAuthorization($authorization) ->setSharedTables(false) ->setTenant(null) ->setNamespace('_' . $project->getSequence()); diff --git a/composer.lock b/composer.lock index 4a212ef6f7..1b06775fe8 100644 --- a/composer.lock +++ b/composer.lock @@ -3844,12 +3844,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "4088c1002bbc837fd9299987cce5d460ded210d1" + "reference": "22123ad30782be131ecad4e9298b843d8daf387b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/4088c1002bbc837fd9299987cce5d460ded210d1", - "reference": "4088c1002bbc837fd9299987cce5d460ded210d1", + "url": "https://api.github.com/repos/utopia-php/database/zipball/22123ad30782be131ecad4e9298b843d8daf387b", + "reference": "22123ad30782be131ecad4e9298b843d8daf387b", "shasum": "" }, "require": { @@ -3894,7 +3894,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance" }, - "time": "2025-10-20T13:53:53+00:00" + "time": "2025-10-27T08:34:29+00:00" }, { "name": "utopia-php/detector", @@ -5318,16 +5318,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.7", + "version": "1.4.12", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "a61c8be551e10f4970bf46f75a54e4b0385c550d" + "reference": "efda55836d19b8d5f36ac0df33c83b48af0aa8fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/a61c8be551e10f4970bf46f75a54e4b0385c550d", - "reference": "a61c8be551e10f4970bf46f75a54e4b0385c550d", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/efda55836d19b8d5f36ac0df33c83b48af0aa8fd", + "reference": "efda55836d19b8d5f36ac0df33c83b48af0aa8fd", "shasum": "" }, "require": { @@ -5363,9 +5363,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.4.7" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.12" }, - "time": "2025-10-22T06:03:44+00:00" + "time": "2025-10-25T05:39:48+00:00" }, { "name": "doctrine/annotations", @@ -6069,16 +6069,16 @@ }, { "name": "phpbench/phpbench", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b" + "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", - "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", + "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", "shasum": "" }, "require": { @@ -6105,7 +6105,7 @@ "ergebnis/composer-normalize": "^2.39", "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", - "phpspec/prophecy": "dev-master", + "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", @@ -6155,7 +6155,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.1" + "source": "https://github.com/phpbench/phpbench/tree/1.4.2" }, "funding": [ { @@ -6163,7 +6163,7 @@ "type": "github" } ], - "time": "2025-03-12T08:01:40+00:00" + "time": "2025-10-26T14:21:59+00:00" }, { "name": "phpstan/phpstan", diff --git a/docker-compose.yml b/docker-compose.yml index b72f12a116..38685354c1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,6 +89,7 @@ services: - ./public:/usr/src/code/public - ./src:/usr/src/code/src - ./dev:/usr/src/code/dev + - ./vendor/utopia-php/database/src:/usr/src/code/vendor/utopia-php/database/src depends_on: - mariadb - redis diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index 5a5e3f223b..bc23a0e130 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -203,7 +203,7 @@ class Create extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Bulk create is not supported for ' . $this->getSDKNamespace() .' with relationship ' . $this->getStructureContext()); } - $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk) { + $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $dbForProject) { $allowedPermissions = [ Database::PERMISSION_READ, Database::PERMISSION_UPDATE, diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index a05dfbd2a4..572736f975 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -155,7 +155,7 @@ class Create extends Base $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRole); + $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); From 037d60633bbfe803e2c099cfcfda8d27c8c3a0d8 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 27 Oct 2025 15:59:20 +0200 Subject: [PATCH 020/167] Add emailCanonical --- app/config/collections/common.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/config/collections/common.php b/app/config/collections/common.php index 2b3d10e457..d8e1c1699a 100644 --- a/app/config/collections/common.php +++ b/app/config/collections/common.php @@ -364,6 +364,17 @@ return [ 'array' => false, 'filters' => ['datetime'], ], + [ + '$id' => ID::custom('emailCanonical'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 320, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('emailIsFree'), 'type' => Database::VAR_BOOLEAN, From 30d58e6371dbf23a29d7a7cd62b739ab4cd4b72f Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 16:14:04 +0200 Subject: [PATCH 021/167] Update composer dependencies for utopia-php/audit and utopia-php/database, reflecting new versioning and aliases. Refactor document validation in Create operation to utilize the new authorization method for better security handling. --- composer.json | 2 +- composer.lock | 35 +++++++++++-------- .../Transactions/Operations/Create.php | 7 ++-- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index f030d0aabf..5225e67d52 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "appwrite/php-clamav": "2.0.*", "utopia-php/abuse": "1.*", "utopia-php/analytics": "0.10.*", - "utopia-php/audit": "1.*", + "utopia-php/audit": "dev-feat-auth-single-instance as 1.1.0", "utopia-php/cache": "0.13.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", diff --git a/composer.lock b/composer.lock index 1b06775fe8..5785529265 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": "a2f032a3d278c7f493ea4d87d6908258", + "content-hash": "d7f36b787ff2fe013d9b866c3823f6d4", "packages": [ { "name": "adhocore/jwt", @@ -3547,21 +3547,21 @@ }, { "name": "utopia-php/audit", - "version": "1.0.2", + "version": "dev-feat-auth-single-instance", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "8c17065c2473d4ca799f65585ca74eb53e1be211" + "reference": "b74a6f8213b444e0af6ce0714ec85ea2859b3508" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/8c17065c2473d4ca799f65585ca74eb53e1be211", - "reference": "8c17065c2473d4ca799f65585ca74eb53e1be211", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/b74a6f8213b444e0af6ce0714ec85ea2859b3508", + "reference": "b74a6f8213b444e0af6ce0714ec85ea2859b3508", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "*" + "utopia-php/database": "dev-feat-authorization-instance as 3.0.2" }, "require-dev": { "laravel/pint": "1.*", @@ -3588,9 +3588,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/1.0.2" + "source": "https://github.com/utopia-php/audit/tree/feat-auth-single-instance" }, - "time": "2025-10-20T07:14:26+00:00" + "time": "2025-10-27T13:39:14+00:00" }, { "name": "utopia-php/cache", @@ -5318,16 +5318,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.12", + "version": "1.4.14", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "efda55836d19b8d5f36ac0df33c83b48af0aa8fd" + "reference": "b9405ccaeac5619c76558a82b7bfeb440b665b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/efda55836d19b8d5f36ac0df33c83b48af0aa8fd", - "reference": "efda55836d19b8d5f36ac0df33c83b48af0aa8fd", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b9405ccaeac5619c76558a82b7bfeb440b665b9f", + "reference": "b9405ccaeac5619c76558a82b7bfeb440b665b9f", "shasum": "" }, "require": { @@ -5363,9 +5363,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.4.12" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.14" }, - "time": "2025-10-25T05:39:48+00:00" + "time": "2025-10-27T11:17:01+00:00" }, { "name": "doctrine/annotations", @@ -8831,6 +8831,12 @@ } ], "aliases": [ + { + "package": "utopia-php/audit", + "version": "dev-feat-auth-single-instance", + "alias": "1.1.0", + "alias_normalized": "1.1.0.0" + }, { "package": "utopia-php/database", "version": "dev-feat-authorization-instance", @@ -8840,6 +8846,7 @@ ], "minimum-stability": "stable", "stability-flags": { + "utopia-php/audit": 20, "utopia-php/database": 20 }, "prefer-stable": false, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index aa3926817e..bea26a2983 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -172,9 +172,12 @@ class Create extends Action $documentValid = false; if ($document !== null && !$document->isEmpty() && $documentSecurity) { if ($permissionType === Database::PERMISSION_UPDATE) { - $documentValid = $validator->isValid($document->getUpdate()); + $documentValid = $dbForProject->getAuthorization()->isValid( + new input(Database::PERMISSION_UPDATE, $document->getUpdate())); } elseif ($permissionType === Database::PERMISSION_DELETE) { - $documentValid = $validator->isValid($document->getDelete()); + $documentValid = $dbForProject->getAuthorization()->isValid( + new input(Database::PERMISSION_DELETE, $document->getDelete()) + ); } } From ecd6880fe0bb7285db7992ec8fe49d5c0f61b3b1 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 16:20:07 +0200 Subject: [PATCH 022/167] composer.lock --- composer.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index 4a212ef6f7..ced7e9d96c 100644 --- a/composer.lock +++ b/composer.lock @@ -3844,12 +3844,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "4088c1002bbc837fd9299987cce5d460ded210d1" + "reference": "22123ad30782be131ecad4e9298b843d8daf387b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/4088c1002bbc837fd9299987cce5d460ded210d1", - "reference": "4088c1002bbc837fd9299987cce5d460ded210d1", + "url": "https://api.github.com/repos/utopia-php/database/zipball/22123ad30782be131ecad4e9298b843d8daf387b", + "reference": "22123ad30782be131ecad4e9298b843d8daf387b", "shasum": "" }, "require": { @@ -3894,7 +3894,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance" }, - "time": "2025-10-20T13:53:53+00:00" + "time": "2025-10-27T08:34:29+00:00" }, { "name": "utopia-php/detector", @@ -5318,16 +5318,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.7", + "version": "1.4.14", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "a61c8be551e10f4970bf46f75a54e4b0385c550d" + "reference": "b9405ccaeac5619c76558a82b7bfeb440b665b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/a61c8be551e10f4970bf46f75a54e4b0385c550d", - "reference": "a61c8be551e10f4970bf46f75a54e4b0385c550d", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b9405ccaeac5619c76558a82b7bfeb440b665b9f", + "reference": "b9405ccaeac5619c76558a82b7bfeb440b665b9f", "shasum": "" }, "require": { @@ -5363,9 +5363,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.4.7" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.14" }, - "time": "2025-10-22T06:03:44+00:00" + "time": "2025-10-27T11:17:01+00:00" }, { "name": "doctrine/annotations", @@ -6069,16 +6069,16 @@ }, { "name": "phpbench/phpbench", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b" + "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", - "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", + "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", "shasum": "" }, "require": { @@ -6105,7 +6105,7 @@ "ergebnis/composer-normalize": "^2.39", "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", - "phpspec/prophecy": "dev-master", + "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", @@ -6155,7 +6155,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.1" + "source": "https://github.com/phpbench/phpbench/tree/1.4.2" }, "funding": [ { @@ -6163,7 +6163,7 @@ "type": "github" } ], - "time": "2025-03-12T08:01:40+00:00" + "time": "2025-10-26T14:21:59+00:00" }, { "name": "phpstan/phpstan", From d7cc3895cba6620c8bf98ca8627a7fb4768ac9e2 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 19:23:55 +0200 Subject: [PATCH 023/167] Update composer.lock to reflect version changes for utopia-php/detector, remove unused registers.php file, and clean up whitespace in cli.php and worker.php. Refactor database resource initialization in resources.php for consistency. --- app/cli.php | 2 +- app/init/registers.php | 342 ------------------ app/init/resources.php | 4 +- app/worker.php | 2 +- composer.lock | 14 +- .../Transactions/Operations/Create.php | 3 +- 6 files changed, 13 insertions(+), 354 deletions(-) delete mode 100644 app/init/registers.php diff --git a/app/cli.php b/app/cli.php index d30e870c30..a70a718948 100644 --- a/app/cli.php +++ b/app/cli.php @@ -185,7 +185,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio $adapter = new DatabasePool($pools->get('logs')); $database = new Database($adapter, $cache); $database->setAuthorization($authorization); - + $database ->setSharedTables(true) ->setNamespace('logsV1') diff --git a/app/init/registers.php b/app/init/registers.php deleted file mode 100644 index 3dc0e22dba..0000000000 --- a/app/init/registers.php +++ /dev/null @@ -1,342 +0,0 @@ -set('logger', function () { - // Register error logger - $providerName = System::getEnv('_APP_LOGGING_PROVIDER', ''); - $providerConfig = System::getEnv('_APP_LOGGING_CONFIG', ''); - - if (empty($providerConfig)) { - return; - } - - try { - $loggingProvider = new DSN($providerConfig ?? ''); - - $providerName = $loggingProvider->getScheme(); - $providerConfig = match ($providerName) { - 'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => 'https://' . $loggingProvider->getHost()], - 'logowl' => ['ticket' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()], - default => ['key' => $loggingProvider->getHost()], - }; - } catch (Throwable $th) { - // Fallback for older Appwrite versions up to 1.5.x that use _APP_LOGGING_PROVIDER and _APP_LOGGING_CONFIG environment variables - Console::warning('Using deprecated logging configuration. Please update your configuration to use DSN format.' . $th->getMessage()); - $configChunks = \explode(";", $providerConfig); - - $providerConfig = match ($providerName) { - 'sentry' => [ 'key' => $configChunks[0], 'projectId' => $configChunks[1] ?? '', 'host' => '',], - 'logowl' => ['ticket' => $configChunks[0] ?? '', 'host' => ''], - default => ['key' => $providerConfig], - }; - } - - if (empty($providerName) || empty($providerConfig)) { - return; - } - - if (!Logger::hasProvider($providerName)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled"); - } - - try { - $adapter = match ($providerName) { - 'sentry' => new Sentry($providerConfig['projectId'], $providerConfig['key'], $providerConfig['host']), - 'logowl' => new LogOwl($providerConfig['ticket'], $providerConfig['host']), - 'raygun' => new Raygun($providerConfig['key']), - 'appsignal' => new AppSignal($providerConfig['key']), - default => null - }; - } catch (Throwable $th) { - $adapter = null; - } - - if ($adapter === null) { - Console::error("Logging provider not supported. Logging is disabled"); - return; - } - - return new Logger($adapter); -}); - -$register->set('pools', function () { - $group = new Group(); - - $fallbackForDB = 'db_main=' . AppwriteURL::unparse([ - 'scheme' => 'mariadb', - 'host' => System::getEnv('_APP_DB_HOST', 'mariadb'), - 'port' => System::getEnv('_APP_DB_PORT', '3306'), - 'user' => System::getEnv('_APP_DB_USER', ''), - 'pass' => System::getEnv('_APP_DB_PASS', ''), - 'path' => System::getEnv('_APP_DB_SCHEMA', ''), - ]); - $fallbackForRedis = 'redis_main=' . AppwriteURL::unparse([ - 'scheme' => 'redis', - 'host' => System::getEnv('_APP_REDIS_HOST', 'redis'), - 'port' => System::getEnv('_APP_REDIS_PORT', '6379'), - 'user' => System::getEnv('_APP_REDIS_USER', ''), - 'pass' => System::getEnv('_APP_REDIS_PASS', ''), - ]); - - $connections = [ - 'console' => [ - 'type' => 'database', - 'dsns' => $fallbackForDB, - 'multiple' => false, - 'schemes' => ['mariadb', 'mysql'], - ], - 'database' => [ - 'type' => 'database', - 'dsns' => $fallbackForDB, - 'multiple' => true, - 'schemes' => ['mariadb', 'mysql'], - ], - 'logs' => [ - 'type' => 'database', - 'dsns' => System::getEnv('_APP_CONNECTIONS_DB_LOGS', $fallbackForDB), - 'multiple' => false, - 'schemes' => ['mariadb', 'mysql'], - ], - 'publisher' => [ - 'type' => 'publisher', - 'dsns' => $fallbackForRedis, - 'multiple' => false, - 'schemes' => ['redis'], - ], - 'consumer' => [ - 'type' => 'consumer', - 'dsns' => $fallbackForRedis, - 'multiple' => false, - 'schemes' => ['redis'], - ], - 'pubsub' => [ - 'type' => 'pubsub', - 'dsns' => $fallbackForRedis, - 'multiple' => false, - 'schemes' => ['redis'], - ], - 'cache' => [ - 'type' => 'cache', - 'dsns' => $fallbackForRedis, - 'multiple' => true, - 'schemes' => ['redis'], - ], - ]; - - $maxConnections = System::getEnv('_APP_CONNECTIONS_MAX', 151); - $instanceConnections = $maxConnections / System::getEnv('_APP_POOL_CLIENTS', 14); - - $multiprocessing = System::getEnv('_APP_SERVER_MULTIPROCESS', 'disabled') === 'enabled'; - - if ($multiprocessing) { - $workerCount = intval(System::getEnv('_APP_CPU_NUM', swoole_cpu_num())) * intval(System::getEnv('_APP_WORKER_PER_CORE', 6)); - } else { - $workerCount = 1; - } - - if ($workerCount > $instanceConnections) { - throw new \Exception('Pool size is too small. Increase the number of allowed database connections or decrease the number of workers.', 500); - } - - $poolSize = (int)($instanceConnections / $workerCount); - - foreach ($connections as $key => $connection) { - $type = $connection['type'] ?? ''; - $multiple = $connection['multiple'] ?? false; - $schemes = $connection['schemes'] ?? []; - $config = []; - $dsns = explode(',', $connection['dsns'] ?? ''); - foreach ($dsns as &$dsn) { - $dsn = explode('=', $dsn); - $name = ($multiple) ? $key . '_' . $dsn[0] : $key; - $dsn = $dsn[1] ?? ''; - $config[] = $name; - if (empty($dsn)) { - //throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}"); - continue; - } - - $dsn = new DSN($dsn); - $dsnHost = $dsn->getHost(); - $dsnPort = $dsn->getPort(); - $dsnUser = $dsn->getUser(); - $dsnPass = $dsn->getPassword(); - $dsnScheme = $dsn->getScheme(); - $dsnDatabase = $dsn->getPath(); - - if (!in_array($dsnScheme, $schemes)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); - } - - /** - * Get Resource - * - * Creation could be reused across connection types like database, cache, queue, etc. - * - * Resource assignment to an adapter will happen below. - */ - $resource = match ($dsnScheme) { - 'mysql', - 'mariadb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { - return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { - return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, [ - \PDO::ATTR_TIMEOUT => 3, // Seconds - \PDO::ATTR_PERSISTENT => false, - \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, - \PDO::ATTR_EMULATE_PREPARES => true, - \PDO::ATTR_STRINGIFY_FETCHES => true - ]); - }); - }, - 'redis' => function () use ($dsnHost, $dsnPort, $dsnPass) { - $redis = new \Redis(); - @$redis->pconnect($dsnHost, (int)$dsnPort); - if ($dsnPass) { - $redis->auth($dsnPass); - } - $redis->setOption(\Redis::OPT_READ_TIMEOUT, -1); - - return $redis; - }, - default => throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid scheme'), - }; - - $pool = new Pool($name, $poolSize, function () use ($type, $resource, $dsn) { - // Get Adapter - switch ($type) { - case 'database': - $adapter = match ($dsn->getScheme()) { - 'mariadb' => new MariaDB($resource()), - 'mysql' => new MySQL($resource()), - default => null - }; - - $adapter->setDatabase($dsn->getPath()); - return $adapter; - case 'pubsub': - return match ($dsn->getScheme()) { - 'redis' => new PubSub($resource()), - default => null - }; - case 'publisher': - case 'consumer': - return match ($dsn->getScheme()) { - 'redis' => new Queue\Broker\Redis(new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort())), - default => null - }; - case 'cache': - return match ($dsn->getScheme()) { - 'redis' => new RedisCache($resource()), - default => null - }; - default: - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); - } - }); - - $group->add($pool); - } - - Config::setParam('pools-' . $key, $config); - } - - return $group; -}); - -$register->set('db', function () { - // This is usually for our workers or CLI commands scope - $dbHost = System::getEnv('_APP_DB_HOST', ''); - $dbPort = System::getEnv('_APP_DB_PORT', ''); - $dbUser = System::getEnv('_APP_DB_USER', ''); - $dbPass = System::getEnv('_APP_DB_PASS', ''); - $dbScheme = System::getEnv('_APP_DB_SCHEMA', ''); - - return new PDO( - "mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", - $dbUser, - $dbPass, - SQL::getPDOAttributes() - ); -}); - -$register->set('smtp', function () { - $mail = new PHPMailer(true); - - $mail->isSMTP(); - - $username = System::getEnv('_APP_SMTP_USERNAME'); - $password = System::getEnv('_APP_SMTP_PASSWORD'); - - $mail->XMailer = 'Appwrite Mailer'; - $mail->Host = System::getEnv('_APP_SMTP_HOST', 'smtp'); - $mail->Port = System::getEnv('_APP_SMTP_PORT', 25); - $mail->SMTPAuth = !empty($username) && !empty($password); - $mail->Username = $username; - $mail->Password = $password; - $mail->SMTPSecure = System::getEnv('_APP_SMTP_SECURE', ''); - $mail->SMTPAutoTLS = false; - $mail->CharSet = 'UTF-8'; - - $from = \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); - $email = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); - - $mail->setFrom($email, $from); - $mail->addReplyTo($email, $from); - - $mail->isHTML(true); - - return $mail; -}); -$register->set('geodb', function () { - return new Reader(__DIR__ . '/../assets/dbip/dbip-country-lite-2024-09.mmdb'); -}); -$register->set('passwordsDictionary', function () { - $content = \file_get_contents(__DIR__ . '/../assets/security/10k-common-passwords'); - $content = explode("\n", $content); - $content = array_flip($content); - return $content; -}); -$register->set('promiseAdapter', function () { - return new Swoole(); -}); -$register->set('hooks', function () { - return new Hooks(); -}); diff --git a/app/init/resources.php b/app/init/resources.php index e85b18d80a..183c83adf4 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -424,10 +424,10 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform }, ['pools', 'dbForPlatform', 'cache', 'project', 'authorization']); App::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authorization $authorization) { - + $adapter = new DatabasePool($pools->get('console')); $database = new Database($adapter, $cache); - + $database ->setAuthorization($authorization) ->setNamespace('_console') diff --git a/app/worker.php b/app/worker.php index 211b4ebfa6..b88d96e3c2 100644 --- a/app/worker.php +++ b/app/worker.php @@ -61,7 +61,7 @@ Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, $dbForPlatform = new Database($adapter, $cache); $dbForPlatform->setAuthorization($authorization); $dbForPlatform->setNamespace('_console'); - + return $dbForPlatform; }, ['cache', 'register', 'authorization']); diff --git a/composer.lock b/composer.lock index 3884b242f1..edb7cb5bf6 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": "d7f36b787ff2fe013d9b866c3823f6d4", + "content-hash": "48764fa55a13051632675cd4a0f7a6fc", "packages": [ { "name": "adhocore/jwt", @@ -3898,16 +3898,16 @@ }, { "name": "utopia-php/detector", - "version": "0.2.0", + "version": "0.1.5", "source": { "type": "git", "url": "https://github.com/utopia-php/detector.git", - "reference": "795ed56169af833fd6a4ea58a6c747e05ccc7ba6" + "reference": "b5d6ba51352485b524589bc0ee8d07a9efafe718" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/detector/zipball/795ed56169af833fd6a4ea58a6c747e05ccc7ba6", - "reference": "795ed56169af833fd6a4ea58a6c747e05ccc7ba6", + "url": "https://api.github.com/repos/utopia-php/detector/zipball/b5d6ba51352485b524589bc0ee8d07a9efafe718", + "reference": "b5d6ba51352485b524589bc0ee8d07a9efafe718", "shasum": "" }, "require": { @@ -3937,9 +3937,9 @@ ], "support": { "issues": "https://github.com/utopia-php/detector/issues", - "source": "https://github.com/utopia-php/detector/tree/0.2.0" + "source": "https://github.com/utopia-php/detector/tree/0.1.5" }, - "time": "2025-10-21T13:57:30+00:00" + "time": "2025-05-19T11:01:28+00:00" }, { "name": "utopia-php/dns", diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index bea26a2983..389cf19c4a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -173,7 +173,8 @@ class Create extends Action if ($document !== null && !$document->isEmpty() && $documentSecurity) { if ($permissionType === Database::PERMISSION_UPDATE) { $documentValid = $dbForProject->getAuthorization()->isValid( - new input(Database::PERMISSION_UPDATE, $document->getUpdate())); + new input(Database::PERMISSION_UPDATE, $document->getUpdate()) + ); } elseif ($permissionType === Database::PERMISSION_DELETE) { $documentValid = $dbForProject->getAuthorization()->isValid( new input(Database::PERMISSION_DELETE, $document->getDelete()) From 681fa198c9bf2a3dffb48f3dcf2f34074c4b5164 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 19:27:16 +0200 Subject: [PATCH 024/167] composer.lock --- composer.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 5785529265..edb7cb5bf6 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": "d7f36b787ff2fe013d9b866c3823f6d4", + "content-hash": "48764fa55a13051632675cd4a0f7a6fc", "packages": [ { "name": "adhocore/jwt", @@ -4344,16 +4344,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.19.0", + "version": "0.20.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "0b866d54e70c792a3c4f5ca9c12a6d358a31f4b8" + "reference": "6c5be4588d97e3732a1907ecb13cd8a098eade96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/0b866d54e70c792a3c4f5ca9c12a6d358a31f4b8", - "reference": "0b866d54e70c792a3c4f5ca9c12a6d358a31f4b8", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/6c5be4588d97e3732a1907ecb13cd8a098eade96", + "reference": "6c5be4588d97e3732a1907ecb13cd8a098eade96", "shasum": "" }, "require": { @@ -4389,9 +4389,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.19.0" + "source": "https://github.com/utopia-php/messaging/tree/0.20.0" }, - "time": "2025-10-14T11:46:49+00:00" + "time": "2025-10-22T04:27:37+00:00" }, { "name": "utopia-php/migration", @@ -5095,16 +5095,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.11.0", + "version": "0.12.0", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "0e665eaa7d906168525bf6aac50b6bcc3e4fe528" + "reference": "28457cf347972c4ec95d3ca77776a4921364a665" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/0e665eaa7d906168525bf6aac50b6bcc3e4fe528", - "reference": "0e665eaa7d906168525bf6aac50b6bcc3e4fe528", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/28457cf347972c4ec95d3ca77776a4921364a665", + "reference": "28457cf347972c4ec95d3ca77776a4921364a665", "shasum": "" }, "require": { @@ -5138,9 +5138,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.11.0" + "source": "https://github.com/utopia-php/vcs/tree/0.12.0" }, - "time": "2025-07-23T13:54:58+00:00" + "time": "2025-10-22T12:58:29+00:00" }, { "name": "utopia-php/websocket", From 26f61c18552cae9155e693bdbf7096d081848e03 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 19:34:49 +0200 Subject: [PATCH 025/167] add back registers.php --- app/init/registers.php | 342 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 app/init/registers.php diff --git a/app/init/registers.php b/app/init/registers.php new file mode 100644 index 0000000000..c64335c09a --- /dev/null +++ b/app/init/registers.php @@ -0,0 +1,342 @@ +set('logger', function () { + // Register error logger + $providerName = System::getEnv('_APP_LOGGING_PROVIDER', ''); + $providerConfig = System::getEnv('_APP_LOGGING_CONFIG', ''); + + if (empty($providerConfig)) { + return; + } + + try { + $loggingProvider = new DSN($providerConfig ?? ''); + + $providerName = $loggingProvider->getScheme(); + $providerConfig = match ($providerName) { + 'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => 'https://' . $loggingProvider->getHost()], + 'logowl' => ['ticket' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()], + default => ['key' => $loggingProvider->getHost()], + }; + } catch (Throwable $th) { + // Fallback for older Appwrite versions up to 1.5.x that use _APP_LOGGING_PROVIDER and _APP_LOGGING_CONFIG environment variables + Console::warning('Using deprecated logging configuration. Please update your configuration to use DSN format.' . $th->getMessage()); + $configChunks = \explode(";", $providerConfig); + + $providerConfig = match ($providerName) { + 'sentry' => [ 'key' => $configChunks[0], 'projectId' => $configChunks[1] ?? '', 'host' => '',], + 'logowl' => ['ticket' => $configChunks[0] ?? '', 'host' => ''], + default => ['key' => $providerConfig], + }; + } + + if (empty($providerName) || empty($providerConfig)) { + return; + } + + if (!Logger::hasProvider($providerName)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled"); + } + + try { + $adapter = match ($providerName) { + 'sentry' => new Sentry($providerConfig['projectId'], $providerConfig['key'], $providerConfig['host']), + 'logowl' => new LogOwl($providerConfig['ticket'], $providerConfig['host']), + 'raygun' => new Raygun($providerConfig['key']), + 'appsignal' => new AppSignal($providerConfig['key']), + default => null + }; + } catch (Throwable $th) { + $adapter = null; + } + + if ($adapter === null) { + Console::error("Logging provider not supported. Logging is disabled"); + return; + } + + return new Logger($adapter); +}); + +$register->set('pools', function () { + $group = new Group(); + + $fallbackForDB = 'db_main=' . AppwriteURL::unparse([ + 'scheme' => 'mariadb', + 'host' => System::getEnv('_APP_DB_HOST', 'mariadb'), + 'port' => System::getEnv('_APP_DB_PORT', '3306'), + 'user' => System::getEnv('_APP_DB_USER', ''), + 'pass' => System::getEnv('_APP_DB_PASS', ''), + 'path' => System::getEnv('_APP_DB_SCHEMA', ''), + ]); + $fallbackForRedis = 'redis_main=' . AppwriteURL::unparse([ + 'scheme' => 'redis', + 'host' => System::getEnv('_APP_REDIS_HOST', 'redis'), + 'port' => System::getEnv('_APP_REDIS_PORT', '6379'), + 'user' => System::getEnv('_APP_REDIS_USER', ''), + 'pass' => System::getEnv('_APP_REDIS_PASS', ''), + ]); + + $connections = [ + 'console' => [ + 'type' => 'database', + 'dsns' => $fallbackForDB, + 'multiple' => false, + 'schemes' => ['mariadb', 'mysql'], + ], + 'database' => [ + 'type' => 'database', + 'dsns' => $fallbackForDB, + 'multiple' => true, + 'schemes' => ['mariadb', 'mysql'], + ], + 'logs' => [ + 'type' => 'database', + 'dsns' => System::getEnv('_APP_CONNECTIONS_DB_LOGS', $fallbackForDB), + 'multiple' => false, + 'schemes' => ['mariadb', 'mysql'], + ], + 'publisher' => [ + 'type' => 'publisher', + 'dsns' => $fallbackForRedis, + 'multiple' => false, + 'schemes' => ['redis'], + ], + 'consumer' => [ + 'type' => 'consumer', + 'dsns' => $fallbackForRedis, + 'multiple' => false, + 'schemes' => ['redis'], + ], + 'pubsub' => [ + 'type' => 'pubsub', + 'dsns' => $fallbackForRedis, + 'multiple' => false, + 'schemes' => ['redis'], + ], + 'cache' => [ + 'type' => 'cache', + 'dsns' => $fallbackForRedis, + 'multiple' => true, + 'schemes' => ['redis'], + ], + ]; + + $maxConnections = System::getEnv('_APP_CONNECTIONS_MAX', 151); + $instanceConnections = $maxConnections / System::getEnv('_APP_POOL_CLIENTS', 14); + + $multiprocessing = System::getEnv('_APP_SERVER_MULTIPROCESS', 'disabled') === 'enabled'; + + if ($multiprocessing) { + $workerCount = intval(System::getEnv('_APP_CPU_NUM', swoole_cpu_num())) * intval(System::getEnv('_APP_WORKER_PER_CORE', 6)); + } else { + $workerCount = 1; + } + + if ($workerCount > $instanceConnections) { + throw new \Exception('Pool size is too small. Increase the number of allowed database connections or decrease the number of workers.', 500); + } + + $poolSize = (int)($instanceConnections / $workerCount); + + foreach ($connections as $key => $connection) { + $type = $connection['type'] ?? ''; + $multiple = $connection['multiple'] ?? false; + $schemes = $connection['schemes'] ?? []; + $config = []; + $dsns = explode(',', $connection['dsns'] ?? ''); + foreach ($dsns as &$dsn) { + $dsn = explode('=', $dsn); + $name = ($multiple) ? $key . '_' . $dsn[0] : $key; + $dsn = $dsn[1] ?? ''; + $config[] = $name; + if (empty($dsn)) { + //throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}"); + continue; + } + + $dsn = new DSN($dsn); + $dsnHost = $dsn->getHost(); + $dsnPort = $dsn->getPort(); + $dsnUser = $dsn->getUser(); + $dsnPass = $dsn->getPassword(); + $dsnScheme = $dsn->getScheme(); + $dsnDatabase = $dsn->getPath(); + + if (!in_array($dsnScheme, $schemes)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); + } + + /** + * Get Resource + * + * Creation could be reused across connection types like database, cache, queue, etc. + * + * Resource assignment to an adapter will happen below. + */ + $resource = match ($dsnScheme) { + 'mysql', + 'mariadb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, [ + \PDO::ATTR_TIMEOUT => 3, // Seconds + \PDO::ATTR_PERSISTENT => false, + \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, + \PDO::ATTR_EMULATE_PREPARES => true, + \PDO::ATTR_STRINGIFY_FETCHES => true + ]); + }); + }, + 'redis' => function () use ($dsnHost, $dsnPort, $dsnPass) { + $redis = new \Redis(); + @$redis->pconnect($dsnHost, (int)$dsnPort); + if ($dsnPass) { + $redis->auth($dsnPass); + } + $redis->setOption(\Redis::OPT_READ_TIMEOUT, -1); + + return $redis; + }, + default => throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid scheme'), + }; + + $pool = new Pool($name, $poolSize, function () use ($type, $resource, $dsn) { + // Get Adapter + switch ($type) { + case 'database': + $adapter = match ($dsn->getScheme()) { + 'mariadb' => new MariaDB($resource()), + 'mysql' => new MySQL($resource()), + default => null + }; + + $adapter->setDatabase($dsn->getPath()); + return $adapter; + case 'pubsub': + return match ($dsn->getScheme()) { + 'redis' => new PubSub($resource()), + default => null + }; + case 'publisher': + case 'consumer': + return match ($dsn->getScheme()) { + 'redis' => new Queue\Broker\Redis(new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort())), + default => null + }; + case 'cache': + return match ($dsn->getScheme()) { + 'redis' => new RedisCache($resource()), + default => null + }; + default: + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); + } + }); + + $group->add($pool); + } + + Config::setParam('pools-' . $key, $config); + } + + return $group; +}); + +$register->set('db', function () { + // This is usually for our workers or CLI commands scope + $dbHost = System::getEnv('_APP_DB_HOST', ''); + $dbPort = System::getEnv('_APP_DB_PORT', ''); + $dbUser = System::getEnv('_APP_DB_USER', ''); + $dbPass = System::getEnv('_APP_DB_PASS', ''); + $dbScheme = System::getEnv('_APP_DB_SCHEMA', ''); + + return new PDO( + "mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", + $dbUser, + $dbPass, + SQL::getPDOAttributes() + ); +}); + +$register->set('smtp', function () { + $mail = new PHPMailer(true); + + $mail->isSMTP(); + + $username = System::getEnv('_APP_SMTP_USERNAME'); + $password = System::getEnv('_APP_SMTP_PASSWORD'); + + $mail->XMailer = 'Appwrite Mailer'; + $mail->Host = System::getEnv('_APP_SMTP_HOST', 'smtp'); + $mail->Port = System::getEnv('_APP_SMTP_PORT', 25); + $mail->SMTPAuth = !empty($username) && !empty($password); + $mail->Username = $username; + $mail->Password = $password; + $mail->SMTPSecure = System::getEnv('_APP_SMTP_SECURE', ''); + $mail->SMTPAutoTLS = false; + $mail->CharSet = 'UTF-8'; + + $from = \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); + $email = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + + $mail->setFrom($email, $from); + $mail->addReplyTo($email, $from); + + $mail->isHTML(true); + + return $mail; +}); +$register->set('geodb', function () { + return new Reader(__DIR__ . '/../assets/dbip/dbip-country-lite-2024-09.mmdb'); +}); +$register->set('passwordsDictionary', function () { + $content = \file_get_contents(__DIR__ . '/../assets/security/10k-common-passwords'); + $content = explode("\n", $content); + $content = array_flip($content); + return $content; +}); +$register->set('promiseAdapter', function () { + return new Swoole(); +}); +$register->set('hooks', function () { + return new Hooks(); +}); \ No newline at end of file From fbaffa980a4aaea288918c27dc54c4b239bb79f2 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 20:46:58 +0200 Subject: [PATCH 026/167] linter --- app/init/registers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/init/registers.php b/app/init/registers.php index c64335c09a..3dc0e22dba 100644 --- a/app/init/registers.php +++ b/app/init/registers.php @@ -339,4 +339,4 @@ $register->set('promiseAdapter', function () { }); $register->set('hooks', function () { return new Hooks(); -}); \ No newline at end of file +}); From e769cf4e487a8f9a52dd9c52c422c8a52405acd2 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 27 Oct 2025 21:23:03 +0200 Subject: [PATCH 027/167] Remove vendor path for utopia-php/database in docker-compose.yml --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1e437356c5..2d2c04ddfd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,7 +89,6 @@ services: - ./public:/usr/src/code/public - ./src:/usr/src/code/src - ./dev:/usr/src/code/dev - - ./vendor/utopia-php/database/src:/usr/src/code/vendor/utopia-php/database/src depends_on: - mariadb - redis From 462634d311c4707fe7f3a12b53e72834d95a808b Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 28 Oct 2025 09:09:54 +0200 Subject: [PATCH 028/167] Update dependencies in composer.json and composer.lock; upgrade utopia-php/detector to version 0.2.*, and utopia-php/migration to version 1.3.3. Modify exception messages in storage API for better clarity on authorization failures. Adjust test assertions to reflect updated error messages. --- app/controllers/api/storage.php | 16 ++++---- composer.json | 2 +- composer.lock | 38 +++++++++---------- .../Transactions/Operations/Create.php | 6 +-- tests/e2e/Services/Tokens/TokensBase.php | 8 ++-- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index ab003bedf1..1224bdd46e 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -991,7 +991,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($file->isEmpty()) { @@ -1171,7 +1171,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $fileSecurity = $bucket->getAttribute('fileSecurity', false); $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($fileSecurity && !$valid && !$isToken) { @@ -1182,7 +1182,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($file->isEmpty()) { @@ -1331,7 +1331,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $fileSecurity = $bucket->getAttribute('fileSecurity', false); $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($fileSecurity && !$valid && !$isToken) { @@ -1342,7 +1342,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($file->isEmpty()) { @@ -1478,7 +1478,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') try { $decoded = $decoder->decode($jwt); } catch (JWTException) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ( @@ -1486,7 +1486,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $decoded['bucketId'] !== $bucketId || $decoded['fileId'] !== $fileId ) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); @@ -1769,7 +1769,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') $fileSecurity = $bucket->getAttribute('fileSecurity', false); $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_DELETE, $bucket->getDelete())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); + throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } // Read permission should not be required for delete diff --git a/composer.json b/composer.json index d53ce2314a..e9b0cebd4d 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", "utopia-php/database": "dev-feat-authorization-instance as 3.0.2", - "utopia-php/detector": "0.1.*", + "utopia-php/detector": "0.2.*", "utopia-php/domains": "0.9.*", "utopia-php/dns": "0.3.*", "utopia-php/dsn": "0.2.1", diff --git a/composer.lock b/composer.lock index edb7cb5bf6..10664cac37 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": "48764fa55a13051632675cd4a0f7a6fc", + "content-hash": "e84237cbb00cc2f2edfa7650cc19c940", "packages": [ { "name": "adhocore/jwt", @@ -3898,16 +3898,16 @@ }, { "name": "utopia-php/detector", - "version": "0.1.5", + "version": "0.2.1", "source": { "type": "git", "url": "https://github.com/utopia-php/detector.git", - "reference": "b5d6ba51352485b524589bc0ee8d07a9efafe718" + "reference": "89f96e864220de13800cf398a1f1686a85401eaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/detector/zipball/b5d6ba51352485b524589bc0ee8d07a9efafe718", - "reference": "b5d6ba51352485b524589bc0ee8d07a9efafe718", + "url": "https://api.github.com/repos/utopia-php/detector/zipball/89f96e864220de13800cf398a1f1686a85401eaa", + "reference": "89f96e864220de13800cf398a1f1686a85401eaa", "shasum": "" }, "require": { @@ -3937,9 +3937,9 @@ ], "support": { "issues": "https://github.com/utopia-php/detector/issues", - "source": "https://github.com/utopia-php/detector/tree/0.1.5" + "source": "https://github.com/utopia-php/detector/tree/0.2.1" }, - "time": "2025-05-19T11:01:28+00:00" + "time": "2025-10-27T13:38:33+00:00" }, { "name": "utopia-php/dns", @@ -4395,16 +4395,16 @@ }, { "name": "utopia-php/migration", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "f5c1d2cae764290766a4c2d1546c1d51de95b67f" + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/f5c1d2cae764290766a4c2d1546c1d51de95b67f", - "reference": "f5c1d2cae764290766a4c2d1546c1d51de95b67f", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/731b3a963c58c30e0b2368695d57a7e8fcb7455c", + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c", "shasum": "" }, "require": { @@ -4444,9 +4444,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.3.2" + "source": "https://github.com/utopia-php/migration/tree/1.3.3" }, - "time": "2025-10-22T12:30:47+00:00" + "time": "2025-10-28T04:02:08+00:00" }, { "name": "utopia-php/mongo", @@ -5318,16 +5318,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.14", + "version": "1.4.15", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "b9405ccaeac5619c76558a82b7bfeb440b665b9f" + "reference": "b4a2fd9e92903c2e156f17fc5dafe102e6cfdfda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b9405ccaeac5619c76558a82b7bfeb440b665b9f", - "reference": "b9405ccaeac5619c76558a82b7bfeb440b665b9f", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b4a2fd9e92903c2e156f17fc5dafe102e6cfdfda", + "reference": "b4a2fd9e92903c2e156f17fc5dafe102e6cfdfda", "shasum": "" }, "require": { @@ -5363,9 +5363,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.4.14" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.15" }, - "time": "2025-10-27T11:17:01+00:00" + "time": "2025-10-28T04:52:59+00:00" }, { "name": "doctrine/annotations", diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index 389cf19c4a..1e90d7f2b5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -167,17 +167,17 @@ class Create extends Action $documentSecurity = $collection->getAttribute('documentSecurity', false); $collectionValid = $dbForProject->getAuthorization()->isValid( - new input($permissionType, $collection->getPermissionsByType($permissionType)) + new Input($permissionType, $collection->getPermissionsByType($permissionType)) ); $documentValid = false; if ($document !== null && !$document->isEmpty() && $documentSecurity) { if ($permissionType === Database::PERMISSION_UPDATE) { $documentValid = $dbForProject->getAuthorization()->isValid( - new input(Database::PERMISSION_UPDATE, $document->getUpdate()) + new Input(Database::PERMISSION_UPDATE, $document->getUpdate()) ); } elseif ($permissionType === Database::PERMISSION_DELETE) { $documentValid = $dbForProject->getAuthorization()->isValid( - new input(Database::PERMISSION_DELETE, $document->getDelete()) + new Input(Database::PERMISSION_DELETE, $document->getDelete()) ); } } diff --git a/tests/e2e/Services/Tokens/TokensBase.php b/tests/e2e/Services/Tokens/TokensBase.php index a4461c06c2..ca6feed5fa 100644 --- a/tests/e2e/Services/Tokens/TokensBase.php +++ b/tests/e2e/Services/Tokens/TokensBase.php @@ -94,7 +94,7 @@ trait TokensBase $this->assertEquals(401, $failedPreview['body']['code']); $this->assertEquals(401, $failedPreview['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedPreview['body']['type']); - $this->assertEquals('The current user is not authorized to perform the requested action.', $failedPreview['body']['message']); + $this->assertEquals('No permissions provided for action \'read\'', $failedPreview['body']['message']); // Extended file preview. Should fail as an anonymous user with no form of any access to the file. $failedCustomPreview = $this->client->call( @@ -113,7 +113,7 @@ trait TokensBase $this->assertEquals(401, $failedCustomPreview['body']['code']); $this->assertEquals(401, $failedCustomPreview['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedCustomPreview['body']['type']); - $this->assertEquals('The current user is not authorized to perform the requested action.', $failedCustomPreview['body']['message']); + $this->assertEquals('No permissions provided for action \'read\'', $failedCustomPreview['body']['message']); // File view. Should fail as an anonymous user with no form of any access to the file. $failedView = $this->client->call( @@ -124,7 +124,7 @@ trait TokensBase $this->assertEquals(401, $failedView['body']['code']); $this->assertEquals(401, $failedView['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedView['body']['type']); - $this->assertEquals('The current user is not authorized to perform the requested action.', $failedView['body']['message']); + $this->assertEquals('No permissions provided for action \'read\'', $failedView['body']['message']); // File download. Should fail as an anonymous user with no form of any access to the file. $failedDownload = $this->client->call( @@ -135,7 +135,7 @@ trait TokensBase $this->assertEquals(401, $failedDownload['body']['code']); $this->assertEquals(401, $failedDownload['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedDownload['body']['type']); - $this->assertEquals('The current user is not authorized to perform the requested action.', $failedDownload['body']['message']); + $this->assertEquals('No permissions provided for action \'read\'', $failedDownload['body']['message']); return $data; } From 4aaaa460b2e241e7e9e2e4fcebf3dbcbc493976f Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Oct 2025 14:13:38 +0530 Subject: [PATCH 029/167] feat: per bucket image transformations flag --- app/config/collections/common.php | 11 ++++ app/config/errors.php | 5 ++ app/controllers/api/storage.php | 19 ++++-- app/controllers/shared/api.php | 4 ++ src/Appwrite/Extend/Exception.php | 1 + src/Appwrite/Migration/Version/V23.php | 10 +++ .../Database/Validator/Queries/Buckets.php | 3 +- src/Appwrite/Utopia/Response/Model/Bucket.php | 6 ++ .../Storage/StorageConsoleClientTest.php | 53 ++++++++++++++++ .../Storage/StorageCustomClientTest.php | 61 +++++++++++++++++++ 10 files changed, 167 insertions(+), 6 deletions(-) diff --git a/app/config/collections/common.php b/app/config/collections/common.php index 6de7eb224b..add08931d1 100644 --- a/app/config/collections/common.php +++ b/app/config/collections/common.php @@ -1527,6 +1527,17 @@ return [ 'required' => true, 'array' => false, ], + [ + '$id' => ID::custom('transformations'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + 'default' => true, + ], [ '$id' => ID::custom('search'), 'type' => Database::VAR_STRING, diff --git a/app/config/errors.php b/app/config/errors.php index 2e18f05797..e9c3894f53 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -522,6 +522,11 @@ return [ 'description' => 'The requested file is not publicly readable.', 'code' => 403, ], + Exception::STORAGE_BUCKET_TRANSFORMATIONS_DISABLED => [ + 'name' => Exception::STORAGE_BUCKET_TRANSFORMATIONS_DISABLED, + 'description' => 'Image transformations are disabled for the requested bucket.', + 'code' => 403, + ], /** Tokens */ Exception::TOKEN_NOT_FOUND => [ diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 8bc383cabd..5494509c89 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -85,10 +85,11 @@ App::post('/v1/storage/buckets') ->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD], true), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) + ->param('transformations', true, new Boolean(true), 'Are image transformations enabled?', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, ?string $compression, ?bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, ?string $compression, ?bool $encryption, bool $antivirus, bool $transformations, Response $response, Database $dbForProject, Event $queueForEvents) { $bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId; @@ -141,6 +142,7 @@ App::post('/v1/storage/buckets') 'compression' => $compression, 'encryption' => $encryption, 'antivirus' => $antivirus, + 'transformations' => $transformations, 'search' => implode(' ', [$bucketId, $name]), ])); @@ -297,10 +299,11 @@ App::put('/v1/storage/buckets/:bucketId') ->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD], true), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) + ->param('transformations', true, new Boolean(true), 'Are image transformations enabled?', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, ?string $compression, ?bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, ?string $compression, ?bool $encryption, bool $antivirus, bool $transformations, Response $response, Database $dbForProject, Event $queueForEvents) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -314,6 +317,7 @@ App::put('/v1/storage/buckets/:bucketId') $encryption ??= $bucket->getAttribute('encryption', true); $antivirus ??= $bucket->getAttribute('antivirus', true); $compression ??= $bucket->getAttribute('compression', Compression::NONE); + $transformations ??= $bucket->getAttribute('transformations', true); // Map aggregate permissions into the multiple permissions they represent. $permissions = Permission::aggregate($permissions); @@ -327,7 +331,8 @@ App::put('/v1/storage/buckets/:bucketId') ->setAttribute('enabled', $enabled) ->setAttribute('encryption', $encryption) ->setAttribute('compression', $compression) - ->setAttribute('antivirus', $antivirus)); + ->setAttribute('antivirus', $antivirus) + ->setAttribute('transformations', $transformations)); $dbForProject->updateCollection('bucket_' . $bucket->getSequence(), $permissions, $fileSecurity); @@ -974,13 +979,17 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') /* @type Document $bucket */ $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isAppUser = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } + if (!$bucket->getAttribute('transformations', true) && !$isAppUser && !$isPrivilegedUser) { + throw new Exception(Exception::STORAGE_BUCKET_TRANSFORMATIONS_DISABLED); + } + $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 959ee77b7d..b9f56f8494 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -594,6 +594,10 @@ App::init() throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } + if (!$bucket->getAttribute('transformations', true) && !$isAppUser && !$isPrivilegedUser) { + throw new Exception(Exception::STORAGE_BUCKET_TRANSFORMATIONS_DISABLED); + } + $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 6f8744568a..5ecc54b86a 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -150,6 +150,7 @@ class Exception extends \Exception public const string STORAGE_INVALID_RANGE = 'storage_invalid_range'; public const string STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id'; public const string STORAGE_FILE_NOT_PUBLIC = 'storage_file_not_public'; + public const string STORAGE_BUCKET_TRANSFORMATIONS_DISABLED = 'storage_bucket_transformations_disabled'; /** VCS */ public const string INSTALLATION_NOT_FOUND = 'installation_not_found'; diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index 7a6d58d59f..fd6973a71e 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -136,6 +136,16 @@ class V23 extends Migration break; } } + + try { + $this->createAttributeFromCollection( + $this->dbForPlatform, + 'buckets', + 'transformations', + ); + } catch (Throwable $th) { + Console::warning("'transformations' from 'buckets': {$th->getMessage()}"); + } } /** diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php b/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php index c4d187520f..ee320a969f 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php @@ -10,7 +10,8 @@ class Buckets extends Base 'fileSecurity', 'maximumFileSize', 'encryption', - 'antivirus' + 'antivirus', + 'transformations', ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/Bucket.php b/src/Appwrite/Utopia/Response/Model/Bucket.php index f5261c026e..f51c8b6527 100644 --- a/src/Appwrite/Utopia/Response/Model/Bucket.php +++ b/src/Appwrite/Utopia/Response/Model/Bucket.php @@ -86,6 +86,12 @@ class Bucket extends Model 'default' => true, 'example' => false, ]) + ->addRule('transformations', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Image transformations are enabled.', + 'default' => true, + 'example' => false, + ]) ; } diff --git a/tests/e2e/Services/Storage/StorageConsoleClientTest.php b/tests/e2e/Services/Storage/StorageConsoleClientTest.php index bbb14fb136..c913816c56 100644 --- a/tests/e2e/Services/Storage/StorageConsoleClientTest.php +++ b/tests/e2e/Services/Storage/StorageConsoleClientTest.php @@ -2,6 +2,7 @@ namespace Tests\E2E\Services\Storage; +use CURLFile; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; @@ -107,4 +108,56 @@ class StorageConsoleClientTest extends Scope $this->assertIsArray($response['body']['imageTransformations']); $this->assertIsNumeric($response['body']['imageTransformationsTotal']); } + public function testCreateBucketTransformationsDisabledConsole(): void + { + // Create a bucket with default settings + $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'bucketId' => ID::unique(), + 'name' => 'Test Console Bucket Transformations Disabled', + ]); + $this->assertEquals(201, $bucket['headers']['status-code']); + + // Create a file in the bucket + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'transformations.png'), + ]); + $this->assertEquals(201, $file['headers']['status-code']); + + // Try to get the file preview + $preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'] . '/preview', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + $this->assertEquals(200, $preview['headers']['status-code']); + + // Update the bucket to disable transformations + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucket['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'name' => 'Test Bucket Transformations Disabled', + 'transformations' => false, + ]); + + // Try to get the file preview again + $preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'] . '/preview', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + $this->assertEquals(200, $preview['headers']['status-code']); // Returns 200 since image transformations are not counted for console requests + + // Delete the bucket + $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + $this->assertEquals(200, $bucket['headers']['status-code']); + } } diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index c723fba50a..71d33165dc 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -1386,4 +1386,65 @@ class StorageCustomClientTest extends Scope $this->assertStringContainsString('users', $file['body']['message']); $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); } + + public function testCreateBucketTransformationsDisabled(): void + { + // Create a bucket with default settings + $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket Transformations Disabled', + 'permissions' => [ + Permission::read(Role::any()) + ], + ]); + $this->assertEquals(201, $bucket['headers']['status-code']); + + // Create a file in the bucket + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', [ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'transformations.png'), + ]); + $this->assertEquals(201, $file['headers']['status-code']); + + // Try to get the file preview + $preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'] . '/preview', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]); + $this->assertEquals(200, $preview['headers']['status-code']); + + // Update the bucket to disable transformations + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucket['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'name' => 'Test Bucket Transformations Disabled', + 'transformations' => false, + ]); + + // Try to get the file preview again + $preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'] . '/preview', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]); + $this->assertEquals(403, $preview['headers']['status-code']); + $this->assertStringContainsString('Image transformations are disabled for the requested bucket.', $preview['body']['message']); + + // Delete the bucket + $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $bucket['headers']['status-code']); + } } From cc6319a2c72b993b62fa1284a7ba8af6131d2c8a Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 28 Oct 2025 11:09:20 +0200 Subject: [PATCH 030/167] singletone fix --- .../TablesDB/Permissions/DatabasesPermissionsGuestTest.php | 4 +++- tests/unit/Auth/AuthTest.php | 6 ++++-- tests/unit/Messaging/MessagingChannelsTest.php | 5 ++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php index 20a91c6717..dde765cfeb 100644 --- a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php @@ -24,7 +24,9 @@ class DatabasesPermissionsGuestTest extends Scope if (isset($this->authorization)) { return $this->authorization; } - return new Authorization(); + + $this->authorization = new Authorization(); + return $this->authorization; } diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 4fef733457..910d10d2ba 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -20,14 +20,16 @@ class AuthTest extends TestCase if (isset($this->authorization)) { return $this->authorization; } - return new Authorization(); + + $this->authorization = new Authorization(); + return $this->authorization; } /** * Reset Roles */ - public function tearDown(): void + public function setUp(): void { $this->getAuthorization()->cleanRoles(); $this->getAuthorization()->addRole(Role::any()->toString()); diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index 54784edada..b6410205a3 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -35,6 +35,7 @@ class MessagingChannelsTest extends TestCase 'functions.1', ]; + private $authorization; public function getAuthorization(): Authorization @@ -42,7 +43,9 @@ class MessagingChannelsTest extends TestCase if (isset($this->authorization)) { return $this->authorization; } - return new Authorization(); + + $this->authorization = new Authorization(); + return $this->authorization; } public function setUp(): void From 68524067cf4c1664d0621558f508fa4fbd4e937b Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 28 Oct 2025 11:29:14 +0200 Subject: [PATCH 031/167] migrations tests fix --- app/controllers/api/migrations.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 294704f7cc..1ea21f9bb5 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -1,5 +1,6 @@ inject('deviceForMigrations') ->inject('queueForEvents') ->inject('queueForMigrations') - ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Device $deviceForFiles, Device $deviceForImports, Event $queueForEvents, Migration $queueForMigrations) { + ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Device $deviceForFiles, Device $deviceForMigrations, Event $queueForEvents, Migration $queueForMigrations) { $isAPIKey = Auth::isAppUser($dbForPlatform->getAuthorization()->getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser($dbForPlatform->getAuthorization()->getRoles()); if ($internalFile && !$isPrivilegedUser) { @@ -497,7 +499,7 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); } - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ($bucket->isEmpty()) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -510,12 +512,12 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } From 1546add5d559c77ad02a5a659db56cab0e09557c Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Oct 2025 15:05:14 +0530 Subject: [PATCH 032/167] add to both dbs --- src/Appwrite/Migration/Version/V23.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index fd6973a71e..82acf40149 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -143,6 +143,16 @@ class V23 extends Migration 'buckets', 'transformations', ); + } catch (Throwable $th) { + Console::warning("(platform) 'transformations' from 'buckets': {$th->getMessage()}"); + } + + try { + $this->createAttributeFromCollection( + $this->dbForProject, + 'buckets', + 'transformations', + ); } catch (Throwable $th) { Console::warning("'transformations' from 'buckets': {$th->getMessage()}"); } From 3f710ddc704d3f3567946e8ec6f967155f18b9df Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Oct 2025 15:06:43 +0530 Subject: [PATCH 033/167] fix: test --- tests/e2e/Services/Storage/StorageConsoleClientTest.php | 4 ++-- tests/e2e/Services/Storage/StorageCustomClientTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/Services/Storage/StorageConsoleClientTest.php b/tests/e2e/Services/Storage/StorageConsoleClientTest.php index c913816c56..5c618d6357 100644 --- a/tests/e2e/Services/Storage/StorageConsoleClientTest.php +++ b/tests/e2e/Services/Storage/StorageConsoleClientTest.php @@ -154,10 +154,10 @@ class StorageConsoleClientTest extends Scope $this->assertEquals(200, $preview['headers']['status-code']); // Returns 200 since image transformations are not counted for console requests // Delete the bucket - $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals(200, $bucket['headers']['status-code']); + $this->assertEquals(204, $response['headers']['status-code']); } } diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index 71d33165dc..ec9f0d0cc7 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -1440,11 +1440,11 @@ class StorageCustomClientTest extends Scope $this->assertStringContainsString('Image transformations are disabled for the requested bucket.', $preview['body']['message']); // Delete the bucket - $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], [ + $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]); - $this->assertEquals(200, $bucket['headers']['status-code']); + $this->assertEquals(204, $response['headers']['status-code']); } } From 7b1e163c7761bfa636ae470710a2628b7b6951a3 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Oct 2025 15:07:24 +0530 Subject: [PATCH 034/167] move to check --- src/Appwrite/Migration/Version/V23.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index 82acf40149..9d724bac0a 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -132,6 +132,14 @@ class V23 extends Migration } $this->dbForProject->purgeCachedCollection($id); break; + case 'buckets': + try { + $this->createAttributeFromCollection($this->dbForProject, $id, 'transformations'); + } catch (Throwable $th) { + Console::warning("'transformations' from {$id}: {$th->getMessage()}"); + } + $this->dbForProject->purgeCachedCollection($id); + break; default: break; } @@ -146,16 +154,6 @@ class V23 extends Migration } catch (Throwable $th) { Console::warning("(platform) 'transformations' from 'buckets': {$th->getMessage()}"); } - - try { - $this->createAttributeFromCollection( - $this->dbForProject, - 'buckets', - 'transformations', - ); - } catch (Throwable $th) { - Console::warning("'transformations' from 'buckets': {$th->getMessage()}"); - } } /** From 0bfbae4cdd2325b2e4dae3aeae1dc5b6ce76e628 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Oct 2025 15:09:11 +0530 Subject: [PATCH 035/167] add to both dbs --- src/Appwrite/Migration/Version/V23.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index 9d724bac0a..07091050d0 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -135,6 +135,7 @@ class V23 extends Migration case 'buckets': try { $this->createAttributeFromCollection($this->dbForProject, $id, 'transformations'); + $this->createAttributeFromCollection($this->dbForPlatform, $id, 'transformations'); } catch (Throwable $th) { Console::warning("'transformations' from {$id}: {$th->getMessage()}"); } @@ -144,16 +145,6 @@ class V23 extends Migration break; } } - - try { - $this->createAttributeFromCollection( - $this->dbForPlatform, - 'buckets', - 'transformations', - ); - } catch (Throwable $th) { - Console::warning("(platform) 'transformations' from 'buckets': {$th->getMessage()}"); - } } /** From ca861119f9bbd6e00f76d63a7ae8e7c1ca61db3f Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Oct 2025 15:10:51 +0530 Subject: [PATCH 036/167] keep in same --- src/Appwrite/Migration/Version/V23.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index 07091050d0..bed744700a 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -135,7 +135,6 @@ class V23 extends Migration case 'buckets': try { $this->createAttributeFromCollection($this->dbForProject, $id, 'transformations'); - $this->createAttributeFromCollection($this->dbForPlatform, $id, 'transformations'); } catch (Throwable $th) { Console::warning("'transformations' from {$id}: {$th->getMessage()}"); } From 9e79d883a06d05dab122bf32986b6128339cf36c Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 28 Oct 2025 14:16:26 +0200 Subject: [PATCH 037/167] Refactor authorization retrieval in realtime and update imports in migration files; clean up whitespace in tests --- app/realtime.php | 3 +-- .../TablesDB/Permissions/DatabasesPermissionsGuestTest.php | 4 ++-- tests/unit/Auth/AuthTest.php | 2 +- tests/unit/Messaging/MessagingChannelsTest.php | 6 +++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/realtime.php b/app/realtime.php index e70b0a152d..75aa625348 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -457,8 +457,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $database = getProjectDB($project); $user = $database->getDocument('users', $userId); - - $roles = $consoleDatabase->getAuthorization()->getRoles($user); + $roles = Auth::getRoles($user, $database->getAuthorization()); $channels = $realtime->connections[$connection]['channels']; $realtime->unsubscribe($connection); diff --git a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php index dde765cfeb..84cb4bce3a 100644 --- a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php @@ -24,9 +24,9 @@ class DatabasesPermissionsGuestTest extends Scope if (isset($this->authorization)) { return $this->authorization; } - + $this->authorization = new Authorization(); - return $this->authorization; + return $this->authorization; } diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 910d10d2ba..06e128003a 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -20,7 +20,7 @@ class AuthTest extends TestCase if (isset($this->authorization)) { return $this->authorization; } - + $this->authorization = new Authorization(); return $this->authorization; } diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index b6410205a3..8fb7f3f666 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -35,7 +35,7 @@ class MessagingChannelsTest extends TestCase 'functions.1', ]; - + private $authorization; public function getAuthorization(): Authorization @@ -43,9 +43,9 @@ class MessagingChannelsTest extends TestCase if (isset($this->authorization)) { return $this->authorization; } - + $this->authorization = new Authorization(); - return $this->authorization; + return $this->authorization; } public function setUp(): void From 0e22b06f0a18a2b794b1f37ca2ebae00179db397 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 28 Oct 2025 15:01:08 +0200 Subject: [PATCH 038/167] linter --- app/controllers/api/migrations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 1ea21f9bb5..db1b867a4b 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -19,8 +19,8 @@ use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; -use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Queries\Documents; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Migration\Resource; use Utopia\Migration\Sources\Appwrite; From 145b8846287678b5bd02a0ada10d07a39e54e016 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 28 Oct 2025 15:07:26 +0200 Subject: [PATCH 039/167] compose.lock --- composer.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 9c732c33ee..aa76cd45d5 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": "e84237cbb00cc2f2edfa7650cc19c940", + "content-hash": "6a0ff41b0f382016b899d52307df5983", "packages": [ { "name": "adhocore/jwt", @@ -7872,16 +7872,16 @@ }, { "name": "symfony/console", - "version": "v7.3.4", + "version": "v7.3.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db" + "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", + "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", "shasum": "" }, "require": { @@ -7946,7 +7946,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.4" + "source": "https://github.com/symfony/console/tree/v7.3.5" }, "funding": [ { @@ -7966,7 +7966,7 @@ "type": "tidelift" } ], - "time": "2025-09-22T15:31:00+00:00" + "time": "2025-10-14T15:46:26+00:00" }, { "name": "symfony/filesystem", @@ -8040,16 +8040,16 @@ }, { "name": "symfony/finder", - "version": "v7.3.2", + "version": "v7.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" + "reference": "9f696d2f1e340484b4683f7853b273abff94421f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", + "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f", + "reference": "9f696d2f1e340484b4683f7853b273abff94421f", "shasum": "" }, "require": { @@ -8084,7 +8084,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.2" + "source": "https://github.com/symfony/finder/tree/v7.3.5" }, "funding": [ { @@ -8104,7 +8104,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2025-10-15T18:45:57+00:00" }, { "name": "symfony/options-resolver", From a6d1f46133c4610adecb976eb3d8d046b4aa3512 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 29 Oct 2025 10:38:09 +0200 Subject: [PATCH 040/167] addressing comments --- app/controllers/api/account.php | 4 +-- app/http.php | 3 +-- composer.lock | 26 +++++++++---------- .../Collections/Documents/Create.php | 8 ++++-- src/Appwrite/Utopia/Request.php | 4 +-- src/Appwrite/Utopia/Response.php | 4 +-- .../DatabasesPermissionsGuestTest.php | 5 +++- tests/unit/Auth/AuthTest.php | 1 + 8 files changed, 31 insertions(+), 24 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 8dfe4b51b7..da7e4c6ff1 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1995,7 +1995,7 @@ App::post('/v1/account/tokens/magic-url') ]); $user->removeAttribute('$sequence'); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); } $tokenSecret = Auth::tokenGenerator(Auth::TOKEN_LENGTH_MAGIC_URL); @@ -2590,7 +2590,7 @@ App::post('/v1/account/tokens/phone') ]); $user->removeAttribute('$sequence'); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); try { $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ diff --git a/app/http.php b/app/http.php index 629d1d21b7..5ca72c45ed 100644 --- a/app/http.php +++ b/app/http.php @@ -457,7 +457,6 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool $request->setAuthorization($authorization); $response->setAuthorization($authorization); - $authorization->cleanRoles(); $authorization->addRole(Role::any()->toString()); @@ -501,7 +500,7 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool $log->addExtra('file', $th->getFile()); $log->addExtra('line', $th->getLine()); $log->addExtra('trace', $th->getTraceAsString()); - $log->addExtra('roles', $authorization->getRoles()); + $log->addExtra('roles', isset($authorization) ? $authorization->getRoles() : []); $sdk = $route->getLabel("sdk", false); diff --git a/composer.lock b/composer.lock index aa76cd45d5..93a4d68546 100644 --- a/composer.lock +++ b/composer.lock @@ -4108,16 +4108,16 @@ }, { "name": "utopia-php/emails", - "version": "0.6.1", + "version": "0.6.2", "source": { "type": "git", "url": "https://github.com/utopia-php/emails.git", - "reference": "0de8896f369b6aa1f14df338645048f95a8439e3" + "reference": "9c4c40cf7c03c2e9e21364566f9b192d03ea93c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/emails/zipball/0de8896f369b6aa1f14df338645048f95a8439e3", - "reference": "0de8896f369b6aa1f14df338645048f95a8439e3", + "url": "https://api.github.com/repos/utopia-php/emails/zipball/9c4c40cf7c03c2e9e21364566f9b192d03ea93c9", + "reference": "9c4c40cf7c03c2e9e21364566f9b192d03ea93c9", "shasum": "" }, "require": { @@ -4125,7 +4125,7 @@ "utopia-php/cli": "^0.15", "utopia-php/domains": "^0.9", "utopia-php/fetch": "^0.4", - "utopia-php/validators": "^0.0.1" + "utopia-php/validators": "^0.0.2" }, "require-dev": { "laravel/pint": "1.25.*", @@ -4162,9 +4162,9 @@ ], "support": { "issues": "https://github.com/utopia-php/emails/issues", - "source": "https://github.com/utopia-php/emails/tree/0.6.1" + "source": "https://github.com/utopia-php/emails/tree/0.6.2" }, - "time": "2025-10-28T07:29:58+00:00" + "time": "2025-10-28T16:08:17+00:00" }, { "name": "utopia-php/fetch", @@ -5109,16 +5109,16 @@ }, { "name": "utopia-php/validators", - "version": "0.0.1", + "version": "0.0.2", "source": { "type": "git", "url": "https://github.com/utopia-php/validators.git", - "reference": "69d1afa5df2f052535764520609e91b491708db2" + "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/validators/zipball/69d1afa5df2f052535764520609e91b491708db2", - "reference": "69d1afa5df2f052535764520609e91b491708db2", + "url": "https://api.github.com/repos/utopia-php/validators/zipball/894210695c5d35fa248fb65f7fe7237b6ff4fb0b", + "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b", "shasum": "" }, "require": { @@ -5149,9 +5149,9 @@ ], "support": { "issues": "https://github.com/utopia-php/validators/issues", - "source": "https://github.com/utopia-php/validators/tree/0.0.1" + "source": "https://github.com/utopia-php/validators/tree/0.0.2" }, - "time": "2025-10-20T15:08:50+00:00" + "time": "2025-10-20T21:52:28+00:00" }, { "name": "utopia-php/vcs", diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index bc23a0e130..011a9f5a52 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -263,13 +263,17 @@ class Create extends Action $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validCollection = $dbForProject->getAuthorization()->isValid(new Input($permission, $collection->getPermissionsByType($permission))); + $validCollection = $dbForProject->getAuthorization()->isValid( + new Input($permission, $collection->getPermissionsByType($permission)) + ); if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$validCollection) { throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); } if ($permission === Database::PERMISSION_UPDATE) { - $validDocument = $dbForProject->getAuthorization()->isValid(new Input($permission, $document->getUpdate())); + $validDocument = $dbForProject->getAuthorization()->isValid( + new Input($permission, $document->getUpdate()) + ); $valid = $validCollection || $validDocument; if ($documentSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index a3820f4f1f..76d87e2012 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -210,7 +210,7 @@ class Request extends UtopiaRequest { $forwardedUserAgent = $this->getHeader('x-forwarded-user-agent'); if (!empty($forwardedUserAgent)) { - $roles = $this->authorization->getRoles(); + $roles = $this->authorization->getRoles() ?? []; $isAppUser = Auth::isAppUser($roles); if ($isAppUser) { @@ -234,7 +234,7 @@ class Request extends UtopiaRequest return md5($this->getURI() . '*' . serialize($params) . '*' . APP_CACHE_BUSTER); } - private Authorization $authorization; + private ?Authorization $authorization = null; public function setAuthorization(Authorization $authorization): void { diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 83ab451c74..c92d49ade8 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -809,7 +809,7 @@ class Response extends SwooleResponse } if ($rule['sensitive']) { - $roles = $this->authorization->getRoles(); + $roles = $this->authorization->getRoles() ?? []; $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -978,7 +978,7 @@ class Response extends SwooleResponse } } - private Authorization $authorization; + private ?Authorization $authorization = null; public function setAuthorization(Authorization $authorization): void { diff --git a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php index 60c4421853..0c9854160e 100644 --- a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php @@ -24,7 +24,10 @@ class DatabasesPermissionsGuestTest extends Scope if (isset($this->authorization)) { return $this->authorization; } - return new Authorization(); + + $this->authorization = new Authorization(); + + return $this->authorization; } public function createCollection(): array diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 06e128003a..5e883bf924 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -22,6 +22,7 @@ class AuthTest extends TestCase } $this->authorization = new Authorization(); + return $this->authorization; } From 9503507011f63515ed4725230cfcba980d4663dd Mon Sep 17 00:00:00 2001 From: Shimon Newman Date: Wed, 29 Oct 2025 11:20:49 +0200 Subject: [PATCH 041/167] Update src/Appwrite/Utopia/Response.php Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/Appwrite/Utopia/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index c92d49ade8..da614a5a6a 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -809,7 +809,7 @@ class Response extends SwooleResponse } if ($rule['sensitive']) { - $roles = $this->authorization->getRoles() ?? []; + $roles = $this->authorization?->getRoles() ?? []; $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); From 111b2abeeb641c9a6cadc5c7c03bbef85707511b Mon Sep 17 00:00:00 2001 From: Shimon Newman Date: Wed, 29 Oct 2025 20:19:49 +0200 Subject: [PATCH 042/167] Update app/cli.php Co-authored-by: Jake Barnby --- app/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/cli.php b/app/cli.php index a70a718948..449f1b444d 100644 --- a/app/cli.php +++ b/app/cli.php @@ -60,7 +60,7 @@ CLI::setResource('pools', function (Registry $register) { CLI::setResource('authorization', function () { $authorization = new Authorization(); $authorization->disable(); - return $authorization; + return $authorization; }, []); CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { From 5c2828bc78aa6e2c5cb483089227f0cf4cc1d083 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 29 Oct 2025 20:21:41 +0200 Subject: [PATCH 043/167] Refactor authorization handling across multiple modules to use a single instance of the Authorization class. --- app/cli.php | 3 +- app/controllers/api/account.php | 140 +++++++------ app/controllers/api/avatars.php | 30 +-- app/controllers/api/messaging.php | 62 +++--- app/controllers/api/migrations.php | 20 +- app/controllers/api/project.php | 10 +- app/controllers/api/storage.php | 186 ++++++++++-------- app/controllers/api/teams.php | 64 +++--- app/controllers/api/users.php | 6 +- app/controllers/api/vcs.php | 61 +++--- .../Modules/Console/Http/Resources/Get.php | 7 +- .../Collections/Attributes/Delete.php | 6 +- .../Databases/Collections/Attributes/Get.php | 6 +- .../Attributes/Relationship/Create.php | 6 +- .../Collections/Attributes/XList.php | 6 +- .../Http/Databases/Collections/Create.php | 6 +- .../Http/Databases/Collections/Delete.php | 6 +- .../Collections/Documents/Action.php | 4 +- .../Documents/Attribute/Decrement.php | 14 +- .../Documents/Attribute/Increment.php | 14 +- .../Collections/Documents/Create.php | 30 +-- .../Collections/Documents/Delete.php | 17 +- .../Databases/Collections/Documents/Get.php | 12 +- .../Collections/Documents/Logs/XList.php | 6 +- .../Collections/Documents/Update.php | 24 +-- .../Collections/Documents/Upsert.php | 24 +-- .../Databases/Collections/Documents/XList.php | 14 +- .../Http/Databases/Collections/Get.php | 6 +- .../Databases/Collections/Indexes/Create.php | 6 +- .../Databases/Collections/Indexes/Delete.php | 6 +- .../Databases/Collections/Indexes/Get.php | 6 +- .../Databases/Collections/Indexes/XList.php | 8 +- .../Http/Databases/Collections/Logs/XList.php | 6 +- .../Http/Databases/Collections/Update.php | 6 +- .../Http/Databases/Collections/Usage/Get.php | 6 +- .../Http/Databases/Collections/XList.php | 6 +- .../Http/Databases/Transactions/Create.php | 6 +- .../Transactions/Operations/Create.php | 26 +-- .../Http/Databases/Transactions/Update.php | 33 ++-- .../Databases/Http/Databases/Usage/Get.php | 6 +- .../Databases/Http/Databases/Usage/XList.php | 6 +- .../Functions/Http/Executions/Create.php | 23 ++- .../Functions/Http/Executions/Delete.php | 7 +- .../Modules/Functions/Http/Executions/Get.php | 11 +- .../Functions/Http/Executions/XList.php | 11 +- .../Functions/Http/Functions/Create.php | 9 +- .../Functions/Http/Functions/Delete.php | 7 +- .../Http/Functions/Deployment/Update.php | 11 +- .../Functions/Http/Functions/Update.php | 7 +- .../Modules/Functions/Http/Usage/Get.php | 6 +- .../Modules/Functions/Http/Usage/XList.php | 6 +- .../Functions/Http/Variables/Create.php | 7 +- .../Functions/Http/Variables/Delete.php | 7 +- .../Functions/Http/Variables/Update.php | 7 +- .../Modules/Sites/Http/Deployments/Create.php | 9 +- .../Http/Deployments/Duplicate/Create.php | 7 +- .../Http/Deployments/Template/Create.php | 7 +- .../Sites/Http/Sites/Deployment/Update.php | 9 +- .../Platform/Modules/Sites/Http/Usage/Get.php | 7 +- .../Modules/Sites/Http/Usage/XList.php | 6 +- .../Http/Tokens/Buckets/Files/Create.php | 8 +- src/Appwrite/Platform/Tasks/Migrate.php | 5 +- .../Platform/Tasks/StatsResources.php | 10 +- 63 files changed, 647 insertions(+), 457 deletions(-) diff --git a/app/cli.php b/app/cli.php index a70a718948..d2e335b795 100644 --- a/app/cli.php +++ b/app/cli.php @@ -149,7 +149,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); - $database->setAuthorization($authorization); + $databases[$dsn->getHost()] = $database; $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); @@ -166,6 +166,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform } $database + ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()); diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index da7e4c6ff1..ca6ac52cd4 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -51,6 +51,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; @@ -169,10 +170,10 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc ; -$createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails) { +$createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { /** @var Utopia\Database\Document $user */ - $userFromRequest = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $userId)); + $userFromRequest = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_INVALID_TOKEN); @@ -218,7 +219,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res $detector->getDevice() )); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session ->setAttribute('$permissions', [ @@ -227,7 +228,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res Permission::delete(Role::user($user->getId())), ])); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); + $authorization->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); $dbForProject->purgeCachedDocument('users', $user->getId()); // Magic URL + Email OTP @@ -323,8 +324,9 @@ App::post('/v1/account') ->inject('user') ->inject('project') ->inject('dbForProject') + ->inject('authorization') ->inject('hooks') - ->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Hooks $hooks) { + ->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Hooks $hooks) { $email = \strtolower($email); if ('console' === $project->getId()) { @@ -402,9 +404,9 @@ App::post('/v1/account') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -430,9 +432,9 @@ App::post('/v1/account') throw new Exception(Exception::USER_ALREADY_EXISTS); } - $dbForProject->getAuthorization()->removeRole(Role::guests()->toString()); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); - $dbForProject->getAuthorization()->addRole(Role::users()->toString()); + $authorization->removeRole(Role::guests()->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::users()->toString()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -893,7 +895,8 @@ App::post('/v1/account/sessions/email') ->inject('queueForEvents') ->inject('queueForMails') ->inject('hooks') - ->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks) { + ->inject('authorization') + ->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks, Authorization $authorization) { $email = \strtolower($email); $protocol = $request->getProtocol(); @@ -936,7 +939,7 @@ App::post('/v1/account/sessions/email') $detector->getDevice() )); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); // Re-hash if not using recommended algo if ($user->getAttribute('hash') !== Auth::DEFAULT_ALGO) { @@ -1028,7 +1031,8 @@ App::post('/v1/account/sessions/anonymous') ->inject('dbForProject') ->inject('geodb') ->inject('queueForEvents') - ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents) { + ->inject('authorization') + ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents, Authorization $authorization) { $protocol = $request->getProtocol(); if ('console' === $project->getId()) { @@ -1073,7 +1077,7 @@ App::post('/v1/account/sessions/anonymous') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $dbForProject->getAuthorization()-> skip(fn () => $dbForProject->createDocument('users', $user)); + $authorization-> skip(fn () => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; @@ -1099,7 +1103,7 @@ App::post('/v1/account/sessions/anonymous') $detector->getDevice() )); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [ Permission::read(Role::user($user->getId())), @@ -1172,6 +1176,7 @@ App::post('/v1/account/sessions/token') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') + ->inject('authorization') ->action($createSession); App::get('/v1/account/sessions/oauth2/:provider') @@ -1364,7 +1369,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('dbForProject') ->inject('geodb') ->inject('queueForEvents') - ->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, array $platforms, Document $devKey, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents) use ($oauthDefaultSuccess) { + ->inject('authorization') + ->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, array $platforms, Document $devKey, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents, Authorization $authorization) use ($oauthDefaultSuccess) { $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https'; $port = $request->getPort(); $callbackBase = $protocol . '://' . $request->getHostname(); @@ -1605,7 +1611,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $userDoc = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $userDoc = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), @@ -1624,8 +1630,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } } - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); - $dbForProject->getAuthorization()->addRole(Role::users()->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::users()->toString()); if (false === $user->getAttribute('status')) { // Account is blocked $failureRedirect(Exception::USER_BLOCKED); // User is in status blocked @@ -1684,7 +1690,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->updateDocument('users', $user->getId(), $user); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $state['success'] = URLParser::parse($state['success']); $query = URLParser::parseQuery($state['success']['query']); @@ -1706,7 +1712,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -1933,7 +1939,8 @@ App::post('/v1/account/tokens/magic-url') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') - ->action(function (string $userId, string $email, string $url, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) { + ->inject('authorization') + ->action(function (string $userId, string $email, string $url, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -1995,7 +2002,7 @@ App::post('/v1/account/tokens/magic-url') ]); $user->removeAttribute('$sequence'); - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); } $tokenSecret = Auth::tokenGenerator(Auth::TOKEN_LENGTH_MAGIC_URL); @@ -2012,7 +2019,7 @@ App::post('/v1/account/tokens/magic-url') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -2185,7 +2192,8 @@ App::post('/v1/account/tokens/email') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') - ->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) { + ->inject('authorization') + ->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -2243,9 +2251,9 @@ App::post('/v1/account/tokens/email') ]); $user->removeAttribute('$sequence'); - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2283,7 +2291,7 @@ App::post('/v1/account/tokens/email') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -2464,6 +2472,7 @@ App::put('/v1/account/sessions/magic-url') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') + ->inject('authorization') ->action($createSession); App::put('/v1/account/sessions/phone') @@ -2505,6 +2514,7 @@ App::put('/v1/account/sessions/phone') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') + ->inject('authorization') ->action($createSession); App::post('/v1/account/tokens/phone') @@ -2545,7 +2555,8 @@ App::post('/v1/account/tokens/phone') ->inject('timelimit') ->inject('queueForStatsUsage') ->inject('plan') - ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { + ->inject('authorization') + ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization) { if (empty(System::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -2590,9 +2601,9 @@ App::post('/v1/account/tokens/phone') ]); $user->removeAttribute('$sequence'); - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2638,7 +2649,7 @@ App::post('/v1/account/tokens/phone') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -3023,7 +3034,8 @@ App::patch('/v1/account/email') ->inject('queueForEvents') ->inject('project') ->inject('hooks') - ->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks) { + ->inject('authorization') + ->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, Authorization $authorization) { // passwordUpdate will be empty if the user has never set a password $passwordUpdate = $user->getAttribute('passwordUpdate'); @@ -3062,7 +3074,7 @@ App::patch('/v1/account/email') ->setAttribute('passwordUpdate', DateTime::now()); } - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('targets', [ + $target = $authorization->skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$email]), ])); @@ -3078,7 +3090,7 @@ App::patch('/v1/account/email') $oldTarget = $user->find('identifier', $oldEmail, 'targets'); if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); + $authorization->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); } $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Duplicate) { @@ -3120,7 +3132,8 @@ App::patch('/v1/account/phone') ->inject('queueForEvents') ->inject('project') ->inject('hooks') - ->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks) { + ->inject('authorization') + ->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, Authorization $authorization) { // passwordUpdate will be empty if the user has never set a password $passwordUpdate = $user->getAttribute('passwordUpdate'); @@ -3133,7 +3146,7 @@ App::patch('/v1/account/phone') $hooks->trigger('passwordValidator', [$dbForProject, $project, $password, &$user, false]); - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('targets', [ + $target = $authorization->skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), ])); @@ -3164,7 +3177,7 @@ App::patch('/v1/account/phone') $oldTarget = $user->find('identifier', $oldPhone, 'targets'); if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); + $authorization->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); } $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Duplicate $th) { @@ -3298,7 +3311,8 @@ App::post('/v1/account/recovery') ->inject('locale') ->inject('queueForMails') ->inject('queueForEvents') - ->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $queueForMails, Event $queueForEvents) { + ->inject('authorization') + ->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $queueForMails, Event $queueForEvents, Authorization $authorization) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); @@ -3334,7 +3348,7 @@ App::post('/v1/account/recovery') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); + $authorization->addRole(Role::user($profile->getId())->toString()); $recovery = $dbForProject->createDocument('tokens', $recovery ->setAttribute('$permissions', [ @@ -3476,7 +3490,8 @@ App::put('/v1/account/recovery') ->inject('project') ->inject('queueForEvents') ->inject('hooks') - ->action(function (string $userId, string $secret, string $password, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents, Hooks $hooks) { + ->inject('authorization') + ->action(function (string $userId, string $secret, string $password, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents, Hooks $hooks, Authorization $authorization) { $profile = $dbForProject->getDocument('users', $userId); if ($profile->isEmpty()) { @@ -3490,7 +3505,7 @@ App::put('/v1/account/recovery') throw new Exception(Exception::USER_INVALID_TOKEN); } - $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); + $authorization->addRole(Role::user($profile->getId())->toString()); $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); @@ -3588,7 +3603,8 @@ App::post('/v1/account/verifications/email') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') - ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) { + ->inject('authorization') + ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); @@ -3617,7 +3633,7 @@ App::post('/v1/account/verifications/email') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $verification = $dbForProject->createDocument('tokens', $verification ->setAttribute('$permissions', [ @@ -3800,9 +3816,10 @@ App::put('/v1/account/verifications/email') ->inject('user') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { + ->inject('authorization') + ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Authorization $authorization) { - $profile = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $userId)); + $profile = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -3815,7 +3832,7 @@ App::put('/v1/account/verifications/email') throw new Exception(Exception::USER_INVALID_TOKEN); } - $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); + $authorization->addRole(Role::user($profile->getId())->toString()); $profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('emailVerification', true)); @@ -3874,7 +3891,8 @@ App::post('/v1/account/verifications/phone') ->inject('timelimit') ->inject('queueForStatsUsage') ->inject('plan') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { + ->inject('authorization') + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization) { if (empty(System::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -3913,7 +3931,7 @@ App::post('/v1/account/verifications/phone') 'ip' => $request->getIP(), ]); - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $verification = $dbForProject->createDocument('tokens', $verification ->setAttribute('$permissions', [ @@ -4018,9 +4036,10 @@ App::put('/v1/account/verifications/phone') ->inject('user') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { + ->inject('authorization') + ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Authorization $authorization) { - $profile = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $userId)); + $profile = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -4032,7 +4051,7 @@ App::put('/v1/account/verifications/phone') throw new Exception(Exception::USER_INVALID_TOKEN); } - $dbForProject->getAuthorization()->addRole(Role::user($profile->getId())->toString()); + $authorization->addRole(Role::user($profile->getId())->toString()); $profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('phoneVerification', true)); @@ -5020,12 +5039,13 @@ App::post('/v1/account/targets/push') ->inject('request') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + ->inject('authorization') + ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) { $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; - $provider = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $provider = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId)); - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if (!$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); @@ -5100,9 +5120,10 @@ App::put('/v1/account/targets/:targetId/push') ->inject('request') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + ->inject('authorization') + ->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) { - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); @@ -5165,8 +5186,9 @@ App::delete('/v1/account/targets/:targetId/push') ->inject('request') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject) { - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + ->inject('authorization') + ->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) { + $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 4952a763fc..0751f0a2a6 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -16,6 +16,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Domains\Domain; use Utopia\Fetch\Client; @@ -66,9 +67,9 @@ $avatarCallback = function (string $type, string $code, int $width, int $height, unset($image); }; -$getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, ?Logger $logger) { +$getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, Authorization $authorization, ?Logger $logger) { try { - $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); $sessions = $user->getAttribute('sessions', []); @@ -119,7 +120,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro ->setAttribute('providerRefreshToken', $refreshToken) ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); + $authorization->skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Throwable $err) { @@ -127,7 +128,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro do { $previousAccessToken = $gitHubSession->getAttribute('providerAccessToken'); - $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); $sessions = $user->getAttribute('sessions', []); $gitHubSession = new Document(); @@ -656,8 +657,9 @@ App::get('/v1/cards/cloud') ->inject('contributors') ->inject('employees') ->inject('logger') - ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { - $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + ->inject('authorization') + ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) { + $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -668,7 +670,7 @@ App::get('/v1/cards/cloud') $email = $user->getAttribute('email', ''); $createdAt = new \DateTime($user->getCreatedAt()); - $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger); + $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger, $authorization); $githubName = $gitHub['name'] ?? ''; $githubId = $gitHub['id'] ?? ''; @@ -863,8 +865,9 @@ App::get('/v1/cards/cloud-back') ->inject('contributors') ->inject('employees') ->inject('logger') - ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { - $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + ->inject('authorization') + ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) { + $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -874,7 +877,7 @@ App::get('/v1/cards/cloud-back') $userId = $user->getId(); $email = $user->getAttribute('email', ''); - $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger); + $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger, $authorization); $githubId = $gitHub['id'] ?? ''; $isHero = \array_key_exists($email, $heroes); @@ -941,8 +944,9 @@ App::get('/v1/cards/cloud-og') ->inject('contributors') ->inject('employees') ->inject('logger') - ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { - $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + ->inject('authorization') + ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) { + $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -957,7 +961,7 @@ App::get('/v1/cards/cloud-og') $email = $user->getAttribute('email', ''); $createdAt = new \DateTime($user->getCreatedAt()); - $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger); + $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger, $authorization); $githubName = $gitHub['name'] ?? ''; $githubId = $gitHub['id'] ?? ''; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 551be5c19c..5caae49864 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -35,6 +35,7 @@ use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Queries; @@ -1068,8 +1069,9 @@ App::get('/v1/messaging/providers') ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -1095,7 +1097,7 @@ App::get('/v1/messaging/providers') } $providerId = $cursor->getValue(); - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); @@ -2473,8 +2475,9 @@ App::get('/v1/messaging/topics') ->param('queries', [], new Topics(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Topics::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -2500,7 +2503,7 @@ App::get('/v1/messaging/topics') } $topicId = $cursor->getValue(); - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Topic '{$topicId}' for the 'cursor' value not found."); @@ -2775,26 +2778,27 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->param('targetId', '', new UID(), 'Target ID. The target ID to link to the specified Topic ID.') ->inject('queueForEvents') ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Authorization $authorization, Response $response) { $subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId; - $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - if (!$dbForProject->getAuthorization()->isValid(new Input('subscribe', $topic->getAttribute('subscribe')))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + if (!$authorization->isValid(new Input('subscribe', $topic->getAttribute('subscribe')))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber = new Document([ '$id' => $subscriberId, @@ -2827,7 +2831,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), }; - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->increaseDocumentAttribute( + $authorization->skip(fn () => $dbForProject->increaseDocumentAttribute( 'topics', $topicId, $totalAttribute, @@ -2871,8 +2875,9 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->param('queries', [], new Subscribers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Response $response) { + ->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -2883,7 +2888,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $queries[] = Query::search('search', $search); } - $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -2906,7 +2911,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') } $subscriberId = $cursor->getValue(); - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); + $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Subscriber '{$subscriberId}' for the 'cursor' value not found."); @@ -2920,10 +2925,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers') throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null."); } - $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { - return function () use ($subscriber, $dbForProject) { - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject, $authorization) { + return function () use ($subscriber, $dbForProject, $authorization) { + $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); return $subscriber ->setAttribute('target', $target) @@ -3057,9 +3062,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') ->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.') ->param('subscriberId', '', new UID(), 'Subscriber ID.') ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) { - $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Authorization $authorization, Response $response) { + $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -3071,8 +3077,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } - $target = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $user = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber ->setAttribute('target', $target) @@ -3108,9 +3114,10 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') ->param('subscriberId', '', new UID(), 'Subscriber ID.') ->inject('queueForEvents') ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Response $response) { - $topic = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + ->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Authorization $authorization, Response $response) { + $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -3133,7 +3140,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), }; - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->decreaseDocumentAttribute( + $authorization->skip(fn () => $dbForProject->decreaseDocumentAttribute( 'topics', $topicId, $totalAttribute, @@ -3689,8 +3696,9 @@ App::get('/v1/messaging/messages') ->param('queries', [], new Messages(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Messages::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') + ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -3716,7 +3724,7 @@ App::get('/v1/messaging/messages') } $messageId = $cursor->getValue(); - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('messages', $messageId)); + $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('messages', $messageId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Message '{$messageId}' for the 'cursor' value not found."); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index db1b867a4b..7d526580ad 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -19,6 +19,7 @@ use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries\Documents; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; @@ -334,18 +335,19 @@ App::post('/v1/migrations/csv/imports') ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') + ->inject('authorization') ->inject('project') ->inject('deviceForFiles') ->inject('deviceForMigrations') ->inject('queueForEvents') ->inject('queueForMigrations') - ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Device $deviceForFiles, Device $deviceForMigrations, Event $queueForEvents, Migration $queueForMigrations) { - $isAPIKey = Auth::isAppUser($dbForPlatform->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForPlatform->getAuthorization()->getRoles()); + ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Authorization $authorization, Document $project, Device $deviceForFiles, Device $deviceForMigrations, Event $queueForEvents, Migration $queueForMigrations) { + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($internalFile && !$isPrivilegedUser) { throw new Exception(Exception::USER_UNAUTHORIZED); } - $bucket = $dbForPlatform->getAuthorization()->skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { + $bucket = $authorization->skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { if ($internalFile) { return $dbForPlatform->getDocument('buckets', 'default'); } @@ -356,7 +358,7 @@ App::post('/v1/migrations/csv/imports') throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = $dbForPlatform->getAuthorization()->skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } @@ -472,6 +474,7 @@ App::post('/v1/migrations/csv/exports') ->inject('user') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->inject('project') ->inject('queueForEvents') ->inject('queueForMigrations') @@ -489,6 +492,7 @@ App::post('/v1/migrations/csv/exports') Document $user, Response $response, Database $dbForProject, + Authorization $authorization, Document $project, Event $queueForEvents, Migration $queueForMigrations @@ -499,7 +503,7 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); } - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ($bucket->isEmpty()) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -512,12 +516,12 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 061711c96a..86f8f786c6 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -14,6 +14,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DateTimeValidator; use Utopia\Database\Validator\UID; use Utopia\Validator\Boolean; @@ -43,9 +44,10 @@ App::get('/v1/project/usage') ->inject('response') ->inject('project') ->inject('dbForProject') + ->inject('authorization') ->inject('getLogsDB') ->inject('smsRates') - ->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, callable $getLogsDB, array $smsRates) { + ->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, Authorization $authorization, callable $getLogsDB, array $smsRates) { $stats = $total = $usage = []; $format = 'Y-m-d 00:00:00'; $firstDay = (new DateTime($startDate))->format($format); @@ -100,7 +102,7 @@ App::get('/v1/project/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) { + $authorization->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) { foreach ($metrics['total'] as $metric) { $db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject; @@ -284,7 +286,7 @@ App::get('/v1/project/usage') }, $dbForProject->find('functions')); // This total is includes free and paid SMS usage - $authPhoneTotal = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->sum('stats', 'value', [ + $authPhoneTotal = $authorization->skip(fn () => $dbForProject->sum('stats', 'value', [ Query::equal('metric', [METRIC_AUTH_METHOD_PHONE]), Query::equal('period', ['1d']), Query::greaterThanEqual('time', $firstDay), @@ -292,7 +294,7 @@ App::get('/v1/project/usage') ])); // This estimate is only for paid SMS usage - $authPhoneMetrics = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('stats', [ + $authPhoneMetrics = $authorization->skip(fn () => $dbForProject->find('stats', [ Query::startsWith('metric', METRIC_AUTH_METHOD_PHONE . '.'), Query::equal('period', ['1d']), Query::greaterThanEqual('time', $firstDay), diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 1224bdd46e..f764b64ef6 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -31,6 +31,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\Query\Cursor; @@ -426,19 +427,20 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('mode') ->inject('deviceForFiles') ->inject('deviceForLocal') - ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceForFiles, Device $deviceForLocal) { + ->inject('authorization') + ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceForFiles, Device $deviceForLocal, Authorization $authorization) { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + if (!$authorization->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } $allowedPermissions = [ @@ -461,7 +463,7 @@ App::post('/v1/storage/buckets/:bucketId/files') } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -474,7 +476,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$dbForProject->getAuthorization()->hasRole($role)) { + if (!$authorization->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -694,10 +696,10 @@ App::post('/v1/storage/buckets/:bucketId/files') * However as with chunk upload even if we are updating, we are essentially creating a file * adding it's new chunk so we validate create permission instead of update */ - if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + if (!$authorization->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } } else { if ($file->isEmpty()) { @@ -736,12 +738,12 @@ App::post('/v1/storage/buckets/:bucketId/files') * However as with chunk upload even if we are updating, we are essentially creating a file * adding it's new chunk so we validate create permission instead of update */ - if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + if (!$authorization->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } try { - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -784,21 +786,22 @@ App::get('/v1/storage/buckets/:bucketId/files') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->inject('mode') - ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, Authorization $authorization, string $mode) { + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } $queries = Query::parseQueries($queries); @@ -827,7 +830,7 @@ App::get('/v1/storage/buckets/:bucketId/files') if ($fileSecurity && !$valid) { $cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($cursorDocument->isEmpty()) { @@ -844,8 +847,8 @@ App::get('/v1/storage/buckets/:bucketId/files') $files = $dbForProject->find('bucket_' . $bucket->getSequence(), $queries); $total = $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT); } else { - $files = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); - $total = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)); + $files = $authorization->skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); + $total = $authorization->skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -884,27 +887,28 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->param('fileId', '', new UID(), 'File ID.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->inject('mode') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Authorization $authorization, string $mode) { + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($file->isEmpty()) { @@ -960,17 +964,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->inject('deviceForFiles') ->inject('deviceForLocal') ->inject('project') - ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Request $request, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal, Document $project) { + ->inject('authorization') + ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Request $request, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal, Document $project, Authorization $authorization) { if (!\extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } /* @type Document $bucket */ - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -978,20 +983,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($file->isEmpty()) { @@ -1109,11 +1114,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; //Do not update transformedAt if it's a console user - if (!Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles())) { + if (!Auth::isPrivilegedUser($authorization->getRoles())) { $transformedAt = $file->getAttribute('transformedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) { $file->setAttribute('transformedAt', DateTime::now()); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); + $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); } } @@ -1153,15 +1158,16 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->inject('request') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->inject('mode') ->inject('resourceToken') ->inject('deviceForFiles') - ->action(function (string $bucketId, string $fileId, ?string $token, Request $request, Response $response, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) { + ->action(function (string $bucketId, string $fileId, ?string $token, Request $request, Response $response, Database $dbForProject, Authorization $authorization, string $mode, Document $resourceToken, Device $deviceForFiles) { /* @type Document $bucket */ - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1169,20 +1175,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($file->isEmpty()) { @@ -1316,12 +1322,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->inject('mode') ->inject('resourceToken') ->inject('deviceForFiles') - ->action(function (string $bucketId, string $fileId, ?string $token, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) { + ->inject('authorization') + ->action(function (string $bucketId, string $fileId, ?string $token, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles, Authorization $authorization) { /* @type Document $bucket */ - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1329,20 +1336,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($file->isEmpty()) { @@ -1470,15 +1477,16 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->inject('project') ->inject('mode') ->inject('deviceForFiles') - ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Document $project, string $mode, Device $deviceForFiles) { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->inject('authorization') + ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Document $project, string $mode, Device $deviceForFiles, Authorization $authorization) { + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $decoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0); try { $decoded = $decoder->decode($jwt); } catch (JWTException) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ( @@ -1486,17 +1494,17 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $decoded['bucketId'] !== $bucketId || $decoded['fileId'] !== $fileId ) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1642,25 +1650,26 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('user') ->inject('mode') ->inject('queueForEvents') - ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $queueForEvents) { + ->inject('authorization') + ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $queueForEvents, Authorization $authorization) { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } // Read permission should not be required for update - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1674,7 +1683,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ]); // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -1687,7 +1696,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$dbForProject->getAuthorization()->hasRole($role)) { + if (!$authorization->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -1708,7 +1717,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $file = $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file); } else { - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1756,33 +1765,34 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('mode') ->inject('deviceForFiles') ->inject('queueForDeletes') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceForFiles, Delete $queueForDeletes) { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->inject('authorization') + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceForFiles, Delete $queueForDeletes, Authorization $authorization) { + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_DELETE, $bucket->getDelete())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_DELETE, $bucket->getDelete())); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } // Read permission should not be required for delete - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } // Make sure we don't delete the file before the document permission check occurs - $validFile = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_DELETE, $file->getDelete())); + $validFile = $authorization->isValid(new Input(Database::PERMISSION_DELETE, $file->getDelete())); if ($fileSecurity && !$valid && !$validFile) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } $deviceDeleted = false; @@ -1806,7 +1816,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $deleted = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId)); + $deleted = $authorization->skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1851,7 +1861,8 @@ App::get('/v1/storage/usage') ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->action(function (string $range, Response $response, Database $dbForProject) { + ->inject('authorization') + ->action(function (string $range, Response $response, Database $dbForProject, Authorization $authorization) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -1863,7 +1874,7 @@ App::get('/v1/storage/usage') ]; $total = []; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), @@ -1941,7 +1952,8 @@ App::get('/v1/storage/:bucketId/usage') ->inject('project') ->inject('dbForProject') ->inject('getLogsDB') - ->action(function (string $bucketId, string $range, Response $response, Document $project, Database $dbForProject, callable $getLogsDB) { + ->inject('authorization') + ->action(function (string $bucketId, string $range, Response $response, Document $project, Database $dbForProject, callable $getLogsDB, Authorization $authorization) { $dbForLogs = call_user_func($getLogsDB, $project); $bucket = $dbForProject->getDocument('buckets', $bucketId); @@ -1959,7 +1971,7 @@ App::get('/v1/storage/:bucketId/usage') str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED), ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $db = ($metric === str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED)) ? $dbForLogs diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 5843cebeca..c208da5c1c 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -41,6 +41,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; @@ -81,16 +82,17 @@ App::post('/v1/teams') ->inject('response') ->inject('user') ->inject('dbForProject') + ->inject('authorization') ->inject('queueForEvents') - ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $isAppUser = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAppUser = Auth::isAppUser($authorization->getRoles()); $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; try { - $team = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('teams', new Document([ + $team = $authorization->skip(fn () => $dbForProject->createDocument('teams', new Document([ '$id' => $teamId, '$permissions' => [ Permission::read(Role::team($teamId)), @@ -485,6 +487,7 @@ App::post('/v1/teams/:teamId/memberships') ->inject('project') ->inject('user') ->inject('dbForProject') + ->inject('authorization') ->inject('locale') ->inject('queueForMails') ->inject('queueForMessaging') @@ -492,9 +495,9 @@ App::post('/v1/teams/:teamId/memberships') ->inject('timelimit') ->inject('queueForStatsUsage') ->inject('plan') - ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { - $isAppUser = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Authorization $authorization, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { + $isAppUser = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); $url = htmlentities($url); if (empty($url)) { @@ -565,7 +568,7 @@ App::post('/v1/teams/:teamId/memberships') try { $userId = ID::unique(); - $invitee = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('users', new Document([ + $invitee = $authorization->skip(fn () => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -601,7 +604,7 @@ App::post('/v1/teams/:teamId/memberships') } } - $isOwner = $dbForProject->getAuthorization()->hasRole('team:' . $team->getId() . '/owner'); + $isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner'); if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team'); @@ -637,11 +640,11 @@ App::post('/v1/teams/:teamId/memberships') ]); $membership = ($isPrivilegedUser || $isAppUser) ? - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('memberships', $membership)) : + $authorization->skip(fn () => $dbForProject->createDocument('memberships', $membership)) : $dbForProject->createDocument('memberships', $membership); if ($isPrivilegedUser || $isAppUser) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + $authorization->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); } } elseif ($membership->getAttribute('confirm') === false) { @@ -654,7 +657,7 @@ App::post('/v1/teams/:teamId/memberships') } $membership = ($isPrivilegedUser || $isAppUser) ? - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) : + $authorization->skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) : $dbForProject->updateDocument('memberships', $membership->getId(), $membership); } else { throw new Exception(Exception::MEMBERSHIP_ALREADY_CONFIRMED); @@ -840,7 +843,8 @@ App::get('/v1/teams/:teamId/memberships') ->inject('response') ->inject('project') ->inject('dbForProject') - ->action(function (string $teamId, array $queries, string $search, Response $response, Document $project, Database $dbForProject) { + ->inject('authorization') + ->action(function (string $teamId, array $queries, string $search, Response $response, Document $project, Database $dbForProject, Authorization $authorization) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -910,7 +914,7 @@ App::get('/v1/teams/:teamId/memberships') 'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true, ]; - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -981,7 +985,8 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') ->inject('response') ->inject('project') ->inject('dbForProject') - ->action(function (string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject) { + ->inject('authorization') + ->action(function (string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject, Authorization $authorization) { $team = $dbForProject->getDocument('teams', $teamId); @@ -1001,7 +1006,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') 'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true, ]; - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -1080,8 +1085,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->inject('user') ->inject('project') ->inject('dbForProject') + ->inject('authorization') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -1098,9 +1104,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::USER_NOT_FOUND); } - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); - $isAppUser = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isOwner = $dbForProject->getAuthorization()->hasRole('team:' . $team->getId() . '/owner'); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAppUser = Auth::isAppUser($authorization->getRoles()); + $isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner'); if ($project->getId() === 'console') { // Quick check: fetch up to 2 owners to determine if only one exists @@ -1181,10 +1187,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->inject('response') ->inject('user') ->inject('dbForProject') + ->inject('authorization') ->inject('project') ->inject('geodb') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Reader $geodb, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Document $project, Reader $geodb, Event $queueForEvents) { $protocol = $request->getProtocol(); $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -1193,7 +1200,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') throw new Exception(Exception::MEMBERSHIP_NOT_FOUND); } - $team = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('teams', $teamId)); + $team = $authorization->skip(fn () => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -1229,11 +1236,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->setAttribute('confirm', true) ; - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); + $authorization->skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); // Create session for the user if not logged in if (!$hasSession) { - $dbForProject->getAuthorization()->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::user($user->getId())->toString()); $detector = new Detector($request->getUserAgent('UNKNOWN')); $record = $geodb->get($request->getIP()); @@ -1261,7 +1268,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $session = $dbForProject->createDocument('sessions', $session); - $dbForProject->getAuthorization()->addRole(Role::user($userId)->toString()); + $authorization->addRole(Role::user($userId)->toString()); if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); @@ -1294,7 +1301,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $dbForProject->purgeCachedDocument('users', $user->getId()); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + $authorization->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); $queueForEvents ->setParam('userId', $user->getId()) @@ -1338,8 +1345,9 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->inject('project') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -1397,7 +1405,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $dbForProject->purgeCachedDocument('users', $profile->getId()); if ($membership->getAttribute('confirm')) { // Count only confirmed members - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); + $authorization->skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); } $queueForEvents diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index d7b4b56806..f7a814c51f 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -43,6 +43,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; @@ -2617,8 +2618,9 @@ App::get('/v1/users/usage') ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->inject('register') - ->action(function (string $range, Response $response, Database $dbForProject) { + ->action(function (string $range, Response $response, Database $dbForProject, Authorization $authorization) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -2628,7 +2630,7 @@ App::get('/v1/users/usage') METRIC_SESSIONS, ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $count => $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 88998dd798..7e46e35299 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -27,6 +27,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Detector\Detection\Framework\Analog; use Utopia\Detector\Detection\Framework\Angular; @@ -70,7 +71,7 @@ use Utopia\VCS\Exception\RepositoryNotFound; use function Swoole\Coroutine\batch; -$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForPlatform, Build $queueForBuilds, callable $getProjectDB, Request $request) { +$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForPlatform, Authorization $authorization, Build $queueForBuilds, callable $getProjectDB, Request $request) { $errors = []; foreach ($repositories as $repository) { try { @@ -81,12 +82,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId } $projectId = $repository->getAttribute('projectId'); - $project = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); $dbForProject = $getProjectDB($project); $resourceCollection = $resourceType === "function" ? 'functions' : 'sites'; $resourceId = $repository->getAttribute('resourceId'); - $resource = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId)); + $resource = $authorization->skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId)); $resourceInternalId = $resource->getSequence(); $deploymentId = ID::unique(); @@ -135,7 +136,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = ''; if (!empty($providerPullRequestId) && $resource->getAttribute('providerSilentMode', false) === false) { - $latestComment = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('vcsComments', [ + $latestComment = $authorization->skip(fn () => $dbForPlatform->findOne('vcsComments', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::equal('providerPullRequestId', [$providerPullRequestId]), Query::orderDesc('$createdAt'), @@ -174,7 +175,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment())); } finally { - Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); + $authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); } } } else { @@ -185,7 +186,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId if (!empty($latestCommentId)) { $teamId = $project->getAttribute('teamId', ''); - $latestComment = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([ + $latestComment = $authorization->skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([ '$id' => ID::unique(), '$permissions' => [ Permission::read(Role::team(ID::custom($teamId))), @@ -206,7 +207,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId } } } elseif (!empty($providerBranch)) { - $latestComments = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('vcsComments', [ + $latestComments = $authorization->skip(fn () => $dbForPlatform->find('vcsComments', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::equal('providerBranch', [$providerBranch]), Query::orderDesc('$createdAt'), @@ -245,7 +246,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment())); } finally { - Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); + $authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); } } } @@ -288,7 +289,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $commands[] = $resource->getAttribute('commands', ''); } - $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('deployments', new Document([ + $deployment = $authorization->skip(fn () => $dbForProject->createDocument('deployments', new Document([ '$id' => $deploymentId, '$permissions' => [ Permission::read(Role::any()), @@ -328,7 +329,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId ->setAttribute('latestDeploymentInternalId', $deployment->getSequence()) ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource)); + $authorization->skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource)); if ($resource->getCollection() === 'sites') { $projectId = $project->getId(); @@ -338,7 +339,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = ID::unique() . "." . $sitesDomain; $ruleId = md5($domain); $previewRuleId = $ruleId; - $dbForProject->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -371,7 +372,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - $dbForProject->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -402,7 +403,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = "commit-" . substr($providerCommitHash, 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - $dbForProject->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -454,7 +455,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId if ($lockAcquired) { // Wrap in try/finally to ensure lock file gets deleted try { - $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId)); + $rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId)); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https'; $previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : ''; @@ -466,7 +467,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()); } } finally { - Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); + $authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); } } } @@ -1382,10 +1383,11 @@ App::post('/v1/vcs/github/events') ->inject('request') ->inject('response') ->inject('dbForPlatform') + ->inject('authorization') ->inject('getProjectDB') ->inject('queueForBuilds') ->action( - function (GitHub $github, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { + function (GitHub $github, Request $request, Response $response, Database $dbForPlatform, Authorization $authorization, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { $payload = $request->getRawPayload(); $signatureRemote = $request->getHeader('x-hub-signature-256', ''); $signatureLocal = System::getEnv('_APP_VCS_GITHUB_WEBHOOK_SECRET', ''); @@ -1421,14 +1423,14 @@ App::post('/v1/vcs/github/events') $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); //find resourceId from relevant resources table - $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::limit(100), ])); // create new deployment only on push (not committed by us) and not when branch is created or deleted if ($providerCommitAuthorEmail !== APP_VCS_GITHUB_EMAIL && !$providerBranchCreated && !$providerBranchDeleted) { - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request); } } elseif ($event == $github::EVENT_INSTALLATION) { if ($parsedPayload["action"] == "deleted") { @@ -1441,16 +1443,16 @@ App::post('/v1/vcs/github/events') ]); foreach ($installations as $installation) { - $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('installationInternalId', [$installation->getSequence()]), Query::limit(1000) ])); foreach ($repositories as $repository) { - $dbForProject->getAuthorization()->skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId())); + $authorization->skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId())); } - Authorization::skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId())); + $authorization->skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId())); } } } elseif ($event == $github::EVENT_PULL_REQUEST) { @@ -1479,12 +1481,12 @@ App::post('/v1/vcs/github/events') $providerCommitAuthor = $commitDetails["commitAuthor"] ?? ''; $providerCommitMessage = $commitDetails["commitMessage"] ?? ''; - $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::orderDesc('$createdAt') ])); - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request); } elseif ($parsedPayload["action"] == "closed") { // Allowed external contributions cleanup @@ -1493,7 +1495,7 @@ App::post('/v1/vcs/github/events') $external = $parsedPayload["external"] ?? true; if ($external) { - $repositories = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::orderDesc('$createdAt') ])); @@ -1504,7 +1506,7 @@ App::post('/v1/vcs/github/events') if (\in_array($providerPullRequestId, $providerPullRequestIds)) { $providerPullRequestIds = \array_diff($providerPullRequestIds, [$providerPullRequestId]); $repository = $repository->setAttribute('providerPullRequestIds', $providerPullRequestIds); - $repository = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); + $repository = $authorization->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); } } } @@ -1691,16 +1693,17 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor ->inject('response') ->inject('project') ->inject('dbForPlatform') + ->inject('authorization') ->inject('getProjectDB') ->inject('queueForBuilds') - ->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForPlatform, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { + ->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForPlatform, Authorization $authorization, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { $installation = $dbForPlatform->getDocument('installations', $installationId); if ($installation->isEmpty()) { throw new Exception(Exception::INSTALLATION_NOT_FOUND); } - $repository = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [ + $repository = $authorization->skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [ Query::equal('projectInternalId', [$project->getSequence()]) ])); @@ -1717,7 +1720,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor // TODO: Delete from array when PR is closed - $repository = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); + $repository = $authorization->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); $privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); $githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID'); @@ -1741,7 +1744,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor $providerBranch = \explode(':', $pullRequestResponse['head']['label'])[1] ?? ''; $providerCommitHash = $pullRequestResponse['head']['sha'] ?? ''; - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerCommitHash, $providerPullRequestId, true, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, '', '', '', '', $providerCommitHash, '', '', '', '', $providerPullRequestId, true, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request); $response->noContent(); }); diff --git a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php index 2abe4e0957..55a60a5cbf 100644 --- a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php +++ b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php @@ -10,6 +10,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Domains\Domain as Domain; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -58,6 +59,7 @@ class Get extends Action ->param('type', '', new WhiteList(['rules']), 'Resource type.') ->inject('response') ->inject('dbForPlatform') + ->inject('authorization') ->callback($this->action(...)); } @@ -65,7 +67,8 @@ class Get extends Action string $value, string $type, Response $response, - Database $dbForPlatform + Database $dbForPlatform, + Authorization $authorization ) { if ($type === 'rules') { $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); @@ -123,7 +126,7 @@ class Get extends Action throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.'); } - $document = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('rules', [ + $document = $authorization()->skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal('domain', [$value]), ])); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php index ec8005993c..07ab604a5a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\IndexDependency as IndexDependencyValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; @@ -66,12 +67,13 @@ class Delete extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { - $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php index 158184e336..d31b17667e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php @@ -9,6 +9,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -67,12 +68,13 @@ class Get extends Action ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php index a502c2012b..411fd3bf5b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php @@ -13,6 +13,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -81,15 +82,16 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $relatedCollectionId, string $type, bool $twoWay, ?string $key, ?string $twoWayKey, string $onDelete, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $relatedCollectionId, string $type, bool $twoWay, ?string $key, ?string $twoWayKey, string $onDelete, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $key ??= $relatedCollectionId; $twoWayKey ??= $collectionId; - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php index e632f6397e..c56a3c5c00 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php @@ -14,6 +14,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -61,12 +62,13 @@ class XList extends Action ->param('queries', [], new Attributes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Attributes::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php index 8a9088382d..71ea9a99a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php @@ -19,6 +19,7 @@ use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -76,12 +77,13 @@ class Create extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php index a9eebbc9d6..67f53fa33a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -63,12 +64,13 @@ class Delete extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index bbf62b2e83..d42dca57fa 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -7,6 +7,7 @@ use Appwrite\Extend\Exception; use Appwrite\Platform\Action as AppwriteAction; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; abstract class Action extends AppwriteAction { @@ -257,6 +258,7 @@ abstract class Action extends AppwriteAction Document $collection, Document $document, Database $dbForProject, + Authorization $authorization, /* options */ array &$collectionsCache, @@ -296,7 +298,7 @@ abstract class Action extends AppwriteAction $relatedCollectionId = $relationship->getAttribute('relatedCollection'); if (!isset($collectionsCache[$relatedCollectionId])) { - $relatedCollectionDoc = $dbForProject->getAuthorization()->skip( + $relatedCollectionDoc = $authorization->skip( fn () => $dbForProject->getDocument( 'database_' . $database->getSequence(), $relatedCollectionId diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php index 9f92a707f8..904f3be95e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php @@ -21,6 +21,7 @@ use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Type as TypeException; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -83,20 +84,21 @@ class Decrement extends Action ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan): void + public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization): void { - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception($this->getParentNotFoundException()); } @@ -104,7 +106,7 @@ class Decrement extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php index b97a937e58..ec23672f98 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php @@ -21,6 +21,7 @@ use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\NotFound as NotFoundException; use Utopia\Database\Exception\Type as TypeException; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -83,20 +84,21 @@ class Increment extends Action ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan): void + public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization): void { - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception($this->getParentNotFoundException()); } @@ -104,7 +106,7 @@ class Increment extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index 011a9f5a52..d7ec69777d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -23,6 +23,7 @@ use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; @@ -131,9 +132,10 @@ class Create extends Action ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void + public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, Authorization $authorization): void { $data = \is_string($data) ? \json_decode($data, true) @@ -177,19 +179,19 @@ class Create extends Action $documents = [$data]; } - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization()->getRoles()); if ($isBulk && !$isAPIKey && !$isPrivilegedUser) { throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE); } - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -246,8 +248,8 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$dbForProject->getAuthorization()->hasRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $dbForProject->getAuthorization()->getRoles()) . ')'); + if (!$authorization()->hasRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $authorization()->getRoles()) . ')'); } } } @@ -263,20 +265,20 @@ class Create extends Action $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validCollection = $dbForProject->getAuthorization()->isValid( + $validCollection = $authorization()->isValid( new Input($permission, $collection->getPermissionsByType($permission)) ); if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$validCollection) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization()->getDescription()); } if ($permission === Database::PERMISSION_UPDATE) { - $validDocument = $dbForProject->getAuthorization()->isValid( + $validDocument = $authorization()->isValid( new Input($permission, $document->getUpdate()) ); $valid = $validCollection || $validDocument; if ($documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization()->getDescription()); } } @@ -301,7 +303,7 @@ class Create extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $dbForProject->getAuthorization()->skip( + $relatedCollection = $authorization()->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -317,7 +319,7 @@ class Create extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $current = $dbForProject->getAuthorization()->skip( + $current = $authorization()->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId()) ); @@ -372,7 +374,7 @@ class Create extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index 325072f97e..fe754b6a68 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -18,6 +18,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Conflict as ConflictException; use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -81,6 +82,7 @@ class Delete extends Action ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } @@ -95,18 +97,19 @@ class Delete extends Action Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, - array $plan + array $plan, + Authorization $authorization ): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -119,7 +122,7 @@ class Delete extends Action // Use transaction-aware document retrieval to see changes from same transaction $document = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $document = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $document = $authorization->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($document->isEmpty()) { @@ -129,7 +132,7 @@ class Delete extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php index 93f66ed989..5dcef98b90 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php @@ -15,6 +15,7 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; @@ -68,20 +69,21 @@ class Get extends Action ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState): void + public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState, Authorization $authorization): void { - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php index 6c38a03ea2..68fd41221d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php @@ -18,6 +18,7 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; @@ -72,12 +73,13 @@ class XList extends Action ->inject('dbForProject') ->inject('locale') ->inject('geodb') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void + public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index a969585b6c..128f57708f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -22,6 +22,7 @@ use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -85,10 +86,11 @@ class Update extends Action ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan): void + public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan, Authorization $authorization): void { $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array @@ -96,16 +98,16 @@ class Update extends Action throw new Exception($this->getMissingPayloadException()); } - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -119,7 +121,7 @@ class Update extends Action // Use transaction-aware document retrieval to see changes from same transaction $document = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $document = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $document = $authorization->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($document->isEmpty()) { @@ -134,7 +136,7 @@ class Update extends Action ]); // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -147,7 +149,7 @@ class Update extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$dbForProject->getAuthorization()->hasRole($role)) { + if (!$authorization->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -189,7 +191,7 @@ class Update extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $dbForProject->getAuthorization()->skip( + $relatedCollection = $authorization->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -206,7 +208,7 @@ class Update extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $oldDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( + $oldDocument = $authorization->skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId() )); @@ -244,7 +246,7 @@ class Update extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 6cf2f646eb..139ff7c466 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -23,6 +23,7 @@ use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -89,10 +90,11 @@ class Upsert extends Action ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Document $user, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan): void + public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Document $user, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan, Authorization $authorization): void { $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array @@ -104,15 +106,15 @@ class Upsert extends Action throw new Exception($this->getMissingPayloadException()); } - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -133,7 +135,7 @@ class Upsert extends Action // Use transaction-aware document retrieval to see changes from same transaction $oldDocument = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $oldDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $oldDocument = $authorization->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($oldDocument->isEmpty()) { if (!empty($user->getId())) { @@ -149,7 +151,7 @@ class Upsert extends Action } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -162,7 +164,7 @@ class Upsert extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$dbForProject->getAuthorization()->hasRole($role)) { + if (!$authorization->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -199,7 +201,7 @@ class Upsert extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $dbForProject->getAuthorization()->skip( + $relatedCollection = $authorization->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -216,7 +218,7 @@ class Upsert extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $oldDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( + $oldDocument = $authorization->skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId() )); @@ -253,7 +255,7 @@ class Upsert extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index dbb30fcc1b..483c34708a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -17,6 +17,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -70,20 +71,21 @@ class XList extends Action ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState): void + public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState, Authorization $authorization): void { - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -111,7 +113,7 @@ class XList extends Action $documentId = $cursor->getValue(); - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId)); + $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId)); if ($cursorDocument->isEmpty()) { $type = ucfirst($this->getContext()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php index 9d4183d75f..725b53ff9e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php @@ -10,6 +10,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -56,12 +57,13 @@ class Get extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php index 7c0d61b588..6afc29a265 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php @@ -16,6 +16,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Index as IndexValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; @@ -78,12 +79,13 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { - $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php index cc6ed66466..89d79ef353 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,12 +70,13 @@ class Delete extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { - $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php index 01b186b2c9..27e0767f88 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php @@ -10,6 +10,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -58,12 +59,13 @@ class Get extends Action ->param('key', null, new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php index 7828b91221..cacfd39f44 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php @@ -15,6 +15,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -63,13 +64,14 @@ class XList extends Action ->param('queries', [], new Indexes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Indexes::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { /** @var Document $database */ - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -109,7 +111,7 @@ class XList extends Action } $indexId = $cursor->getValue(); - $cursorDocument = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('indexes', [ + $cursorDocument = $authorization->skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionInternalId', [$collection->getSequence()]), Query::equal('databaseInternalId', [$database->getSequence()]), Query::equal('key', [$indexId]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php index a7f24e7c2b..928ba55ee0 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php @@ -18,6 +18,7 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; @@ -71,12 +72,13 @@ class XList extends Action ->inject('dbForProject') ->inject('locale') ->inject('geodb') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void + public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php index 116b8cdccf..d1760089f6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Helpers\Permission; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,12 +70,13 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php index 9ade789cb9..beca779bf6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php @@ -14,6 +14,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\WhiteList; @@ -62,10 +63,11 @@ class Get extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $range, string $collectionId, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $range, string $collectionId, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { $database = $dbForProject->getDocument('databases', $databaseId); $collectionDocument = $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId); @@ -82,7 +84,7 @@ class Get extends Action str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getSequence(), $collectionDocument->getSequence()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php index 43b4d59255..9e3829abe4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php @@ -15,6 +15,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -64,12 +65,13 @@ class XList extends Action ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, array $queries, string $search, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, array $queries, string $search, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php index cd01a03ca4..41d3f3022a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; +use Utopia\Database\Validator\Authorization; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Range; @@ -54,10 +55,11 @@ class Create extends Action ->inject('response') ->inject('dbForProject') ->inject('user') + ->inject('authorization') ->callback($this->action(...)); } - public function action(int $ttl, UtopiaResponse $response, Database $dbForProject, Document $user): void + public function action(int $ttl, UtopiaResponse $response, Database $dbForProject, Document $user, Authorization $authorization): void { $permissions = []; if (!empty($user->getId())) { @@ -72,7 +74,7 @@ class Create extends Action } } - $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('transactions', new Document([ + $transaction = $authorization->skip(fn () => $dbForProject->createDocument('transactions', new Document([ '$id' => ID::unique(), '$permissions' => $permissions, 'status' => 'pending', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index 1e90d7f2b5..98a0708f66 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -17,6 +17,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -63,21 +64,22 @@ class Create extends Action ->inject('dbForProject') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $transactionId, array $operations, UtopiaResponse $response, Database $dbForProject, TransactionState $transactionState, array $plan): void + public function action(string $transactionId, array $operations, UtopiaResponse $response, Database $dbForProject, TransactionState $transactionState, array $plan, Authorization $authorization): void { if (empty($operations)) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Operations array cannot be empty'); } - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); // API keys and admins can read any transaction, regular users need permissions $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -113,13 +115,13 @@ class Create extends Action throw new Exception(Exception::USER_UNAUTHORIZED); } - $database = $databases[$operation['databaseId']] ??= $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $operation['databaseId'])); + $database = $databases[$operation['databaseId']] ??= $authorization->skip(fn () => $dbForProject->getDocument('databases', $operation['databaseId'])); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = $collections[$operation[$this->getGroupId()]] ??= - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $operation[$this->getGroupId()])); + $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $operation[$this->getGroupId()])); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -166,17 +168,17 @@ class Create extends Action if (!$isAPIKey && !$isPrivilegedUser) { $documentSecurity = $collection->getAttribute('documentSecurity', false); - $collectionValid = $dbForProject->getAuthorization()->isValid( + $collectionValid = $authorization->isValid( new Input($permissionType, $collection->getPermissionsByType($permissionType)) ); $documentValid = false; if ($document !== null && !$document->isEmpty() && $documentSecurity) { if ($permissionType === Database::PERMISSION_UPDATE) { - $documentValid = $dbForProject->getAuthorization()->isValid( + $documentValid = $authorization->isValid( new Input(Database::PERMISSION_UPDATE, $document->getUpdate()) ); } elseif ($permissionType === Database::PERMISSION_DELETE) { - $documentValid = $dbForProject->getAuthorization()->isValid( + $documentValid = $authorization->isValid( new Input(Database::PERMISSION_DELETE, $document->getDelete()) ); } @@ -195,7 +197,7 @@ class Create extends Action // Users can only set permissions for roles they have if (isset($operation['data']['$permissions'])) { $permissions = $operation['data']['$permissions']; - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -207,7 +209,7 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$dbForProject->getAuthorization()->hasRole($role)) { + if (!$authorization->hasRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -236,7 +238,7 @@ class Create extends Action } } - $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { + $transaction = $authorization->skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { $dbForProject->createDocuments('transactionLogs', $staged); return $dbForProject->increaseDocumentAttribute( 'transactions', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index ec43cfa87f..24e149800d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -76,6 +76,7 @@ class Update extends Action ->inject('queueForRealtime') ->inject('queueForFunctions') ->inject('queueForWebhooks') + ->inject('authorization') ->callback($this->action(...)); } @@ -102,7 +103,7 @@ class Update extends Action * @throws Structure * @throws \Utopia\Exception */ - public function action(string $transactionId, bool $commit, bool $rollback, UtopiaResponse $response, Database $dbForProject, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks): void + public function action(string $transactionId, bool $commit, bool $rollback, UtopiaResponse $response, Database $dbForProject, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, Authorization $authorization): void { if (!$commit && !$rollback) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Either commit or rollback must be true'); @@ -111,11 +112,11 @@ class Update extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Cannot commit and rollback at the same time'); } - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); $transaction = ($isAPIKey || $isPrivilegedUser) - ? $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -138,11 +139,11 @@ class Update extends Action try { $dbForProject->withTransaction(function () use ($dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, $queueForEvents, $queueForStatsUsage, $queueForRealtime, $queueForFunctions, $queueForWebhooks) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'committing', ]))); - $operations = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('transactionLogs', [ + $operations = $authorization->skip(fn () => $dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX), @@ -218,7 +219,7 @@ class Update extends Action } } - $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument( + $transaction = $authorization->skip(fn () => $dbForProject->updateDocument( 'transactions', $transactionId, new Document(['status' => 'committed']) @@ -230,32 +231,32 @@ class Update extends Action }); } catch (NotFoundException $e) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::DOCUMENT_NOT_FOUND, previous: $e); } catch (DuplicateException|ConflictException $e) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::TRANSACTION_CONFLICT, previous: $e); } catch (StructureException $e) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage()); } catch (LimitException $e) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, $e->getMessage()); } catch (TransactionException $e) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::TRANSACTION_FAILED, $e->getMessage()); } catch (QueryException $e) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); @@ -283,11 +284,11 @@ class Update extends Action $data = $data->getArrayCopy(); } - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('databases', [ + $database = $authorization->skip(fn () => $dbForProject->findOne('databases', [ Query::equal('$sequence', [$databaseInternalId]) ])); - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->findOne('database_' . $databaseInternalId, [ + $collection = $authorization->skip(fn () => $dbForProject->findOne('database_' . $databaseInternalId, [ Query::equal('$sequence', [$collectionInternalId]) ])); @@ -379,7 +380,7 @@ class Update extends Action } if ($rollback) { - $transaction = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument( + $transaction = $authorization->skip(fn () => $dbForProject->updateDocument( 'transactions', $transactionId, new Document(['status' => 'failed']) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php index f75506e5cf..7668ad0a79 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php @@ -13,6 +13,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Swoole\Response as SwooleResponse; @@ -58,10 +59,11 @@ class Get extends Action ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $range, UtopiaResponse $response, Database $dbForProject): void + public function action(string $databaseId, string $range, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { $database = $dbForProject->getDocument('databases', $databaseId); @@ -80,7 +82,7 @@ class Get extends Action str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES) ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php index 5927f98a02..757f845c68 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php @@ -12,6 +12,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\WhiteList; @@ -55,10 +56,11 @@ class XList extends Action ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $range, UtopiaResponse $response, Database $dbForProject): void + public function action(string $range, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { $periods = Config::getParam('usage', []); @@ -73,7 +75,7 @@ class XList extends Action METRIC_DATABASES_OPERATIONS_WRITES, ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index 572736f975..a3b9b31380 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -26,6 +26,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; @@ -93,6 +94,7 @@ class Create extends Base ->inject('queueForFunctions') ->inject('geodb') ->inject('executor') + ->inject('authorization') ->callback($this->action(...)); } @@ -114,7 +116,8 @@ class Create extends Base StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, - Executor $executor + Executor $executor, + Authorization $authorization ) { $async = \strval($async) === 'true' || \strval($async) === '1'; @@ -152,10 +155,10 @@ class Create extends Base throw new Exception($validator->getDescription(), 400); } - $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); @@ -171,7 +174,7 @@ class Create extends Base throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } - $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''))); + $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''))); if ($deployment->getAttribute('resourceId') !== $function->getId()) { throw new Exception(Exception::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function'); @@ -185,8 +188,8 @@ class Create extends Base throw new Exception(Exception::BUILD_NOT_READY); } - if (!$dbForProject->getAuthorization()->isValid(new Input('execute', $function->getAttribute('execute')))) { // Check if user has write access to execute function - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + if (!$authorization->isValid(new Input('execute', $function->getAttribute('execute')))) { // Check if user has write access to execute function + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } $jwt = ''; // initialize @@ -284,7 +287,7 @@ class Create extends Base if ($async) { if (is_null($scheduledAt)) { - $execution = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); $queueForFunctions ->setType('http') ->setExecution($execution) @@ -325,7 +328,7 @@ class Create extends Base ->setAttribute('scheduleInternalId', $schedule->getSequence()) ->setAttribute('scheduledAt', $scheduledAt); - $execution = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); } return $response @@ -478,7 +481,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))) ; - $execution = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); } $executionResponse['headers']['x-appwrite-execution-id'] = $execution->getId(); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php index c9dffc82b8..ccf345dbb5 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php @@ -13,6 +13,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -60,6 +61,7 @@ class Delete extends Base ->inject('dbForProject') ->inject('dbForPlatform') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } @@ -69,7 +71,8 @@ class Delete extends Base Response $response, Database $dbForProject, Database $dbForPlatform, - Event $queueForEvents + Event $queueForEvents, + Authorization $authorization ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -107,7 +110,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('active', false); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php index 1f11976b8a..69c4080f8a 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php @@ -10,6 +10,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -51,6 +52,7 @@ class Get extends Base ->param('executionId', '', new UID(), 'Execution ID.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } @@ -58,12 +60,13 @@ class Get extends Base string $functionId, string $executionId, Response $response, - Database $dbForProject + Database $dbForProject, + Authorization $authorization ) { - $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php index 3cd07b6cea..0237689b88 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php @@ -15,6 +15,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Order as OrderException; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; @@ -57,6 +58,7 @@ class XList extends Base ->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } @@ -64,12 +66,13 @@ class XList extends Base string $functionId, array $queries, Response $response, - Database $dbForProject + Database $dbForProject, + Authorization $authorization ) { - $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index 6105aa49c7..182f39e274 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -27,6 +27,7 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -114,6 +115,7 @@ class Create extends Base ->inject('dbForPlatform') ->inject('request') ->inject('gitHub') + ->inject('authorization') ->callback($this->action(...)); } @@ -151,7 +153,8 @@ class Create extends Base Func $queueForFunctions, Database $dbForPlatform, Request $request, - GitHub $github + GitHub $github, + Authorization $authorization ) { // Temporary abuse check @@ -236,7 +239,7 @@ class Create extends Base throw new Exception(Exception::FUNCTION_ALREADY_EXISTS); } - $schedule = $dbForProject->getAuthorization()->skip( + $schedule = $authorization->skip( fn () => $dbForPlatform->createDocument('schedules', new Document([ 'region' => $project->getAttribute('region'), 'resourceType' => SCHEDULE_RESOURCE_TYPE_FUNCTION, @@ -364,7 +367,7 @@ class Create extends Base // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $rule = $dbForPlatform->getAuthorization()->skip( + $rule = $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php index 5b87031fa0..6c9c9c3c6f 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php @@ -13,6 +13,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -60,6 +61,7 @@ class Delete extends Base ->inject('queueForDeletes') ->inject('queueForEvents') ->inject('dbForPlatform') + ->inject('authorization') ->callback($this->action(...)); } @@ -69,7 +71,8 @@ class Delete extends Base Database $dbForProject, DeleteEvent $queueForDeletes, Event $queueForEvents, - Database $dbForPlatform + Database $dbForPlatform, + Authorization $authorization ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -86,7 +89,7 @@ class Delete extends Base $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('active', false); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queueForDeletes ->setType(DELETE_TYPE_DOCUMENT) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index c1851e3eb3..b913848a13 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -13,6 +13,7 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -61,6 +62,7 @@ class Update extends Base ->inject('dbForProject') ->inject('queueForEvents') ->inject('dbForPlatform') + ->inject('authorization') ->callback($this->action(...)); } @@ -71,7 +73,8 @@ class Update extends Base Response $response, Database $dbForProject, Event $queueForEvents, - Database $dbForPlatform + Database $dbForPlatform, + Authorization $authorization ) { $function = $dbForProject->getDocument('functions', $functionId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -100,7 +103,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queries = [ Query::equal('trigger', ['manual']), @@ -111,12 +114,12 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { + $authorization->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment, $authorization) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }, $queries)); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php index d571d81d84..d182bb67ea 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php @@ -22,6 +22,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; @@ -103,6 +104,7 @@ class Update extends Base ->inject('dbForPlatform') ->inject('gitHub') ->inject('executor') + ->inject('authorization') ->callback($this->action(...)); } @@ -133,7 +135,8 @@ class Update extends Base Build $queueForBuilds, Database $dbForPlatform, GitHub $github, - Executor $executor + Executor $executor, + Authorization $authorization ) { // TODO: If only branch changes, re-deploy $function = $dbForProject->getDocument('functions', $functionId); @@ -281,7 +284,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queueForEvents->setParam('functionId', $function->getId()); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php index 501b6bb468..1fa65d0cc9 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php @@ -12,6 +12,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -54,10 +55,11 @@ class Get extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $functionId, string $range, Response $response, Database $dbForProject) + public function action(string $functionId, string $range, Response $response, Database $dbForProject, Authorization $authorization) { $function = $dbForProject->getDocument('functions', $functionId); @@ -82,7 +84,7 @@ class Get extends Base str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_FAILED), ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php index 2b8308a75a..38a95d4469 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php @@ -11,6 +11,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\WhiteList; @@ -51,10 +52,11 @@ class XList extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $range, Response $response, Database $dbForProject) + public function action(string $range, Response $response, Database $dbForProject, Authorization $authorization) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -74,7 +76,7 @@ class XList extends Base str_replace("{resourceType}", RESOURCE_TYPE_FUNCTIONS, METRIC_RESOURCE_TYPE_BUILDS_FAILED), ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php index 4aedbdabc5..c61a610617 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php @@ -20,6 +20,7 @@ use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; use Utopia\Validator\Text; +use Utopia\Database\Validator\Authorization; class Create extends Base { @@ -64,6 +65,7 @@ class Create extends Base ->inject('dbForProject') ->inject('dbForPlatform') ->inject('project') + ->inject('authorization') ->callback($this->action(...)); } @@ -75,7 +77,8 @@ class Create extends Base Response $response, Database $dbForProject, Database $dbForPlatform, - Document $project + Document $project, + Authorization $authorization ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -118,7 +121,7 @@ class Create extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response ->setStatusCode(Response::STATUS_CODE_CREATED) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php index ecbdf3e13b..0ab315b212 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php @@ -14,6 +14,7 @@ use Utopia\Database\DateTime; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\Database\Validator\Authorization; class Delete extends Base { @@ -56,6 +57,7 @@ class Delete extends Base ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') + ->inject('authorization') ->callback($this->action(...)); } @@ -64,7 +66,8 @@ class Delete extends Base string $variableId, Response $response, Database $dbForProject, - Database $dbForPlatform + Database $dbForPlatform, + Authorization $authorization ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -91,7 +94,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->noContent(); } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php index d83af69a0b..e581c3e887 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php @@ -16,6 +16,7 @@ use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; use Utopia\Validator\Text; +use Utopia\Database\Validator\Authorization; class Update extends Base { @@ -60,6 +61,7 @@ class Update extends Base ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') + ->inject('authorization') ->callback($this->action(...)); } @@ -71,7 +73,8 @@ class Update extends Base ?bool $secret, Response $response, Database $dbForProject, - Database $dbForPlatform + Database $dbForPlatform, + Authorization $authorization ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -108,7 +111,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->dynamic($variable, Response::MODEL_VARIABLE); } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index 9e3812bb1c..b590f7c1d3 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -29,6 +29,7 @@ use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Text; +use Utopia\Database\Validator\Authorization; class Create extends Action { @@ -85,6 +86,7 @@ class Create extends Action ->inject('deviceForLocal') ->inject('queueForBuilds') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } @@ -104,7 +106,8 @@ class Create extends Action Device $deviceForSites, Device $deviceForLocal, Build $queueForBuilds, - array $plan + array $plan, + Authorization $authorization ) { $activate = \strval($activate) === 'true' || \strval($activate) === '1'; @@ -273,7 +276,7 @@ class Create extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $dbForPlatform->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -338,7 +341,7 @@ class Create extends Action $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); $domain = ID::unique() . "." . $sitesDomain; $ruleId = md5($domain); - $dbForPlatform->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php index 4a3b7c804f..21f86aea35 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php @@ -12,6 +12,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -64,6 +65,7 @@ class Create extends Action ->inject('queueForEvents') ->inject('queueForBuilds') ->inject('deviceForSites') + ->inject('authorization') ->callback($this->action(...)); } @@ -77,7 +79,8 @@ class Create extends Action Database $dbForPlatform, Event $queueForEvents, Build $queueForBuilds, - Device $deviceForSites + Device $deviceForSites, + Authorization $authorization ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -145,7 +148,7 @@ class Create extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $dbForPlatform->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index 5888040476..7909b5ca3e 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -23,6 +23,7 @@ use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Text; use Utopia\VCS\Adapter\Git\GitHub; +use Utopia\Database\Validator\Authorization; class Create extends Base { @@ -76,6 +77,7 @@ class Create extends Base ->inject('queueForEvents') ->inject('queueForBuilds') ->inject('gitHub') + ->inject('authorization') ->callback($this->action(...)); } @@ -93,7 +95,8 @@ class Create extends Base Document $project, Event $queueForEvents, Build $queueForBuilds, - GitHub $github + GitHub $github, + Authorization $authorization ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -175,7 +178,7 @@ class Create extends Base // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $dbForPlatform->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index d89014f7d8..382039f85d 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -12,6 +12,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -59,6 +60,7 @@ class Update extends Base ->inject('dbForProject') ->inject('queueForEvents') ->inject('dbForPlatform') + ->inject('authorization') ->callback($this->action(...)); } @@ -69,7 +71,8 @@ class Update extends Base Response $response, Database $dbForProject, Event $queueForEvents, - Database $dbForPlatform + Database $dbForPlatform, + Authorization $authorization ) { $site = $dbForProject->getDocument('sites', $siteId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -103,12 +106,12 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { + $authorization->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }, $queries)); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php index ca1ef5d9f3..5c274d6a20 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php @@ -12,6 +12,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -54,6 +55,7 @@ class Get extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } @@ -61,7 +63,8 @@ class Get extends Base string $siteId, string $range, Response $response, - Database $dbForProject + Database $dbForProject, + Authorization $authorization ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -90,7 +93,7 @@ class Get extends Base ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php index f29ca2bec3..a90cb0cab9 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php @@ -11,6 +11,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\WhiteList; @@ -51,10 +52,11 @@ class XList extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $range, Response $response, Database $dbForProject) + public function action(string $range, Response $response, Database $dbForProject, Authorization $authorization) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -77,7 +79,7 @@ class XList extends Base METRIC_SITES_OUTBOUND, ]; - $dbForProject->getAuthorization()->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index e0f51308d4..0a5a3da15b 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -13,6 +13,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; @@ -65,10 +66,11 @@ class Create extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { /** @@ -78,10 +80,10 @@ class Create extends Action ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $bucketPermission = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); + $bucketPermission = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); if ($fileSecurity) { - $filePermission = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_UPDATE, $file->getUpdate())); + $filePermission = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $file->getUpdate())); if (!$bucketPermission && !$filePermission) { throw new Exception(Exception::USER_UNAUTHORIZED); } diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 4bab864653..1fd7525937 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -9,6 +9,7 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Exception; +use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Validator\Text; @@ -30,6 +31,7 @@ class Migrate extends Action ->inject('dbForPlatform') ->inject('getProjectDB') ->inject('register') + ->inject('authorization') ->callback($this->action(...)); } @@ -46,8 +48,9 @@ class Migrate extends Action Database $dbForPlatform, callable $getProjectDB, Registry $register, + Authorization $authorization ): void { - $dbForPlatform->getAuthorization()->disable(); + $authorization->disable(); if (!\array_key_exists($version, Migration::$versions)) { Console::error("No migration found for version $version."); diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index 345c855920..b7da5d227d 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -8,6 +8,7 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\System\System; /** @@ -44,10 +45,11 @@ class StatsResources extends Action ->inject('dbForPlatform') ->inject('logError') ->inject('queueForStatsResources') + ->inject('authorization') ->callback($this->action(...)); } - public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue): void + public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue, Authorization $authorization): void { $this->logError = $logError; $this->dbForPlatform = $dbForPlatform; @@ -60,9 +62,9 @@ class StatsResources extends Action $interval = (int) System::getEnv('_APP_STATS_RESOURCES_INTERVAL', '3600'); - Console::loop(function () use ($queue, $dbForPlatform) { - $dbForPlatform->getAuthorization()->disable(); - $dbForPlatform->getAuthorization()->setDefaultStatus(false); + Console::loop(function () use ($queue, $dbForPlatform, $authorization) { + $authorization->disable(); + $authorization->setDefaultStatus(false); $last24Hours = (new \DateTime())->sub(\DateInterval::createFromDateString('24 hours')); /** From 68b0fe8c70ecaee27ffc6a076db31021b93ea1a6 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 29 Oct 2025 20:33:36 +0200 Subject: [PATCH 044/167] linter --- app/cli.php | 2 +- app/worker.php | 18 +++++++++++------- .../Functions/Http/Variables/Create.php | 2 +- .../Functions/Http/Variables/Delete.php | 4 ++-- .../Functions/Http/Variables/Update.php | 2 +- .../Modules/Sites/Http/Deployments/Create.php | 2 +- .../Sites/Http/Deployments/Template/Create.php | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/cli.php b/app/cli.php index 4186aff6b7..0900926346 100644 --- a/app/cli.php +++ b/app/cli.php @@ -185,9 +185,9 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio $adapter = new DatabasePool($pools->get('logs')); $database = new Database($adapter, $cache); - $database->setAuthorization($authorization); $database + ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK) diff --git a/app/worker.php b/app/worker.php index c54d9183b4..319be088d5 100644 --- a/app/worker.php +++ b/app/worker.php @@ -59,8 +59,10 @@ Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, $pools = $register->get('pools'); $adapter = new DatabasePool($pools->get('console')); $dbForPlatform = new Database($adapter, $cache); - $dbForPlatform->setAuthorization($authorization); - $dbForPlatform->setNamespace('_console'); + + $dbForPlatform + ->setAuthorization($authorization) + ->setNamespace('_console'); return $dbForPlatform; @@ -93,7 +95,7 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); - $database->setAuthorization($authorization); + $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); if (\in_array($dsn->getHost(), $sharedTables)) { @@ -108,7 +110,9 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, ->setNamespace('_' . $project->getSequence()); } - $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); + $database + ->setAuthorization($authorization) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); return $database; }, ['cache', 'register', 'message', 'project', 'dbForPlatform', 'authorization']); @@ -149,9 +153,7 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf } $adapter = new DatabasePool($pools->get($dsn->getHost())); - $adapter->setAuthorization($authorization); $database = new Database($adapter, $cache); - $database->setAuthorization($authorization); $databases[$dsn->getHost()] = $database; @@ -169,7 +171,9 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf ->setNamespace('_' . $project->getSequence()); } - $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); + $database + ->setAuthorization($authorization) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); return $database; }; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php index c61a610617..ae74bfa98a 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php @@ -15,12 +15,12 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; use Utopia\Validator\Text; -use Utopia\Database\Validator\Authorization; class Create extends Base { diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php index 0ab315b212..dcb80e4c8c 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php @@ -11,10 +11,10 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; -use Utopia\Database\Validator\Authorization; class Delete extends Base { @@ -94,7 +94,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->noContent(); } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php index e581c3e887..7a97a53650 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php @@ -11,12 +11,12 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Exception\Duplicate as DuplicateException; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; use Utopia\Validator\Text; -use Utopia\Database\Validator\Authorization; class Update extends Base { diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index b590f7c1d3..ff20d27334 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -17,6 +17,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -29,7 +30,6 @@ use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Text; -use Utopia\Database\Validator\Authorization; class Create extends Action { diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index 7909b5ca3e..377b3321ae 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -15,6 +15,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -23,7 +24,6 @@ use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Text; use Utopia\VCS\Adapter\Git\GitHub; -use Utopia\Database\Validator\Authorization; class Create extends Base { From e40e88c32233d42ae5ded50a43eb34e98e71389e Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 30 Oct 2025 18:09:36 +0200 Subject: [PATCH 045/167] Update emails attributes --- app/controllers/api/account.php | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 5563fc6a59..68cf189395 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -57,6 +57,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; +use Utopia\Emails\Email as EmailCanonical; use Utopia\Locale\Locale; use Utopia\Storage\Validator\FileName; use Utopia\System\System; @@ -1674,7 +1675,15 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if (empty($user->getAttribute('email'))) { - $user->setAttribute('email', $oauth2->getUserEmail($accessToken)); + $emailCanonical = new EmailCanonical($oauth2->getUserEmail($accessToken)); + + $user + ->setAttribute('email', $oauth2->getUserEmail($accessToken)) + ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) + ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) + ->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()) + ->setAttribute('emailIsFree', $emailCanonical->isFree()); } if (empty($user->getAttribute('name'))) { @@ -2219,6 +2228,8 @@ App::post('/v1/account/tokens/email') $userId = $userId === 'unique()' ? ID::unique() : $userId; + $emailCanonical = new EmailCanonical($email); + $user->setAttributes([ '$id' => $userId, '$permissions' => [ @@ -2241,6 +2252,11 @@ App::post('/v1/account/tokens/email') 'memberships' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), + 'emailCanonical' => $emailCanonical->getCanonical(), + 'emailIsCanonical' => $emailCanonical->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical->isCorporate(), + 'emailIsDisposable' => $emailCanonical->isDisposable(), + 'emailIsFree' => $emailCanonical->isFree(), ]); $user->removeAttribute('$sequence'); @@ -3050,9 +3066,17 @@ App::patch('/v1/account/email') throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */ } + $emailCanonical = new EmailCanonical($email); + $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again + ->setAttribute('emailVerification', false) + ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) + ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) + ->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()) + ->setAttribute('emailIsFree', $emailCanonical->isFree()) ; if (empty($passwordUpdate)) { From fea16309092535dd3ac5017136cffa206518312c Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 30 Oct 2025 18:18:09 +0200 Subject: [PATCH 046/167] Remove redundant emailVerification --- app/controllers/api/account.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 68cf189395..cdd7280fb7 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -3071,7 +3071,6 @@ App::patch('/v1/account/email') $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again - ->setAttribute('emailVerification', false) ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) From 458100cd69f426ba0ae43c31efb050535a14e559 Mon Sep 17 00:00:00 2001 From: Steven Nguyen <1477010+stnguyen90@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:42:18 -0700 Subject: [PATCH 047/167] Upgrade base image to version 0.10.5 Ensure libwebp is installed in the base image when imagemagick is installed so that imagemagick works with webp. --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2a3e176838..1f5df230d9 100755 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ --no-plugins --no-scripts --prefer-dist \ `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi` -FROM appwrite/base:0.10.4 AS final +FROM appwrite/base:0.10.5 AS final LABEL maintainer="team@appwrite.io" @@ -28,8 +28,6 @@ RUN \ apk add boost boost-dev; \ fi -RUN apk add libwebp - WORKDIR /usr/src/code COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor From ce539972a54053ed14993c0586d393363219bfbb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:51:50 +0000 Subject: [PATCH 048/167] Initial plan From de4f473da192ed954ee734bb456a7d545c8aa974 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:56:12 +0000 Subject: [PATCH 049/167] Initial plan for adding webp test cases Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- tests/resources/logo.webp | Bin 0 -> 17200 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/resources/logo.webp diff --git a/tests/resources/logo.webp b/tests/resources/logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..f9bde111dbbd3ff06345f7fa53a29c2013d42f9f GIT binary patch literal 17200 zcmeHtQ*bU^vu14Dwr$(Vj&1GOwr$(CZSQ!;wr#!1eCJHnslR5X=IY$c)ZbTK>!Pc> z*IM0ALs?ovf=Uz!NJCsiNnMGH2=5>M?gKa%n5F@&0ZiZ*RkB2JQDGqoDix9g477#a zmjm~~oPe?QvApKb%kH7SEg#Y04}~A-SN>J~>)f_t9<1U^{jEWPKc#@VJNlZzqrizD zeoyw(?tTB3;JE+w_urp?Xlw2{|Kx|gzZ^jMUH*OgCD>tquK50QXK>0y6a!F04Sz zTzM-ipi`Iref)2q{QE)tfBPHqzatrB7U9f=G(j_IM;KD~V3G7B#p;o|+*KrqU}8Bg z@y_>2S9r@fEMPA(8Lp2>xXNYK=I^D%B=Yo$UH&CF5E6mygd6c?%_GWx_~sE0`Ajmsfvw)!**n8I>){kE7XWQrX%O(s+B zHLoo2PUpQnZFsl?KOhlt5@aTjy8_uyRNI8oPxb~QjSV8cCyRfX8HUXOc2zs6N=O1C zKb6}eeM*UA99gqVs>rIQ&G=%JWf&TRL}s+3+rL+dzwPWe6lyzOs0SUq^!F!bQa(75 zfF!8?G?VyXSX-HEgbZIMdaOtlH@c8p=7FM~Ag`X5?0I;H7-tx6WR8Wmb=@|kyYrwN z!+xk?tj`=B{0G)EI~I3EKJkDw*^a6599>x4|69l?kfy+X-~pVKd(A7E`6}9zE+aMB_@m}VyUV-{-kBq`Np-=F>0=D`F2@xt zpJp{Tg1{P?UNdOg<1KGH94rz~_(W+4b88!I(y&`izKS9}E5xCxtU5o+9(sn&4;5uJ zGA3xm`YsF}K8!(V%oW7)3zSI+zF>RD0_cZ`tU3II#RG}3|TC&WC97_h#Kw)(~E@QNxixO&Hw~`>(vw&xF@R}?p3}fjpgmy(=n&OnX zu~uAdO^KLUY!r2+yPuHpa-kcSi?IU;S+mRt$mf7>cbTgR(yn`YOMQYiQzvY-;gq2K zFlU`Z1}ePOj+wQaq7@M;&{0o3b9eX-!$nMmXl}SR;X=#6@1mM6lYo+dDINKyESTnf zy|tB@mh6qO;*3$OFX$%Me05>h7EUWE;DNM+)HDc(=dq}>k^|mCT6CM)(pi{vhC0sT zVfxbm=7BjGrvwq0;M;=zrA&H}QNUoj`MfF794~VyL!(gapS;^s=N%k~VyBJ-NlU~# zt7_5Vp~}FjE`ypHU7A*p5@s8a^?}6PE48Avm4<3`bm>NKAco^CF}<0gQ{>ZhrMY>8?TKNOXL|xlL^?6f2 zab0R<25HOH6>CJw;mD)0l-?JiF454vZac!Q_q97|wXPRY*sHnJS*!c3_sS+@&S3sS9@%B~;qVEp4>y_&zIBFNGBrZ?s13JMsSu92)lsJ^qgn`mX~1 zce%>@BFgL;s!AtE5ny7Y>NSLx$rwmwe;`H)W?kG=>ptCNrE-7jJOy4)s~(ajeO;3#tK%L>F=|!^SY;BZ~Iq;jv#Vz{5lWVJ_9OK zm3g{QoixW)3^?(DwOte-;`OSqN?B0l+2 zGK8db#HD=84^V3ay zlJI){JvHYP8gkI`8j=^kaO^d8*t4^7A?cuy(Kb^vB{i|-vycv|&mjAXLQL%a!< z^sTIztFRZG9J1nSxX>HhuEyYS!gBSf$b66;<1><59>jm9lmB@^|Ki^vB) z#v{;|^T&(uV13l`p=Z|&Q}!1VL`W$M zW-vH^GU6XiZECE2RTx=Cw5y4?;0!|6xS*@m!hP&Sq9t9MLoQAq)1imAhD~IW02epR zKk8JjSM4hMWqSbN;q{Asck5iMY;QV*un5Jkb)wX{)F_peTbALDkB12yDTir!@}u8bHsRZ|kU zD;8OZo?S~Y8=P>}c{GuMjA%@Wg32nTaz4l7%IK8CZ?%L*^Xj+8uh)S`{7~N-T{Sf=X z?WZa1Lbs7=cMH*PyiabCPbyH~2|m}$fE9<`D)7k9IHxcXv|aH3Ca+sds- z__cY8LLIp`k{yW>iYY`qj{bSvl~!lR3M-wSQVYhv5P?(-rTGjnmu6-+gj!OK9LL~ur`+r_oInA z6^|^$0%{06new1yDN97!EJ0RQ!{W7*#>AkaA$IxCar9T z2UJd@S|`h4JDD2kPg*B9J^}j0&7*>Yl}TOX5O0S?rUo|bs750h9adW!@fmE|DGm$W zYa2%1T!wtQ+>|LcvS%=2-Cg|+@KM>B`nU8u@9`DAhTeqKn{N6jCF957^1q}iV~WH4 zAMBj`R!R5b#jcZ4*e~oR&J(q$892;;%lJ>{h3`@~`_}DYKzW)uoiUz;yK3AFsly3$ z;Lx|%y_+6ihK*kwBm!cr(*t##QrPm%K7R$uefLqoPG)?R5)<*ejz9zx*_YTPV;7)CR*pjB=TH*yUqA)5D- zqpXYvne1RdDs1#HcTLQ-1c{G3d%02v*(H^s&|d=yD4MN}4v(2;=%;4669eUk=V!6M zt^u8tFkqn0zUCKNvQz9%Ol> z=o5fS5fx_;!`(L0bGYbB3$<sj)1L6;jw1MZ``=C)lO7c4CnAQZr-+}`4Yw4y~n z)PTDwG|(6By-3EdY0}%;li!sye{}8wp_HlMkOjzUlYmRfE_N0{GuQiSqjUy{%NS5d&u5!`G(hk-oLPG(!N*D%$KL(JqlxsJzeU z{ABAg7&~{!8nF=r^;61l znNP%2<0E1&Lc@EL*6a`1O}vk#g7#FJpmt?fARk;d?$yyU0zzT0a* zJIY>DT!v%^{hgx(0Uj$+LXdwHH~b5V;S8N*AczcS=f|pneOdICMMFJnG;Q&{Bm{YV zfm3%+T<2)A4)XCwS^66&S5XByBCwtghZ zbbu2)t`#W_Ph476P<`FblM85Fx5wkfhc%%m^pDl#X#_FnZ=zB5f~ou1UgcIXK!nLnYy>iMK7rcoVJ!_q#N?eBQV0px z7(ChzoRws&xpxCc$B!>ba4Oo+wa+lftOD`i{*;ligVitNu|y4uh5bHrEqP|<$07eT zw$l=wK|Bs#FlXJ`mEz<%f8~VqObPOhU>~&yay!jquYF2GP!oQ}Vp#V_MQ#ZwwoG~N zW(!UVkA~r_Ha;QCGUtx;xs@zYMg&O~z01IV0cH&%P}L^PW~x!~tGO!d%XQ9iAEeF( zcAVe;Zqpx>4w_=iilhlV=VmO|0E z3GC>9=`s~KnYZ*+`WYW0R60S4z8eOs7#|U3Dkf@5qjOPk-@~OES}Toeg9~2Fr%|ca z!M*Bfgs+IR#sNEC4QAH?2L3ZP|e?ZRee9myb` zzP%8&3mQ9;n6!X(JI_ORKP#18r{~bXwMKbJ&K|YoDTyH$dzLU+HZ%?8Q3GeWz<;1w zv@LPNgRexYBrH>8ebSv6ITjH$ePPf5k@rZr$%kCB=%Yus_ZhAb{MA3~A%m6th$dj; zHa9XxEiw-fdm#erVC-F^Y8fRiRcK-tx|xnv=1*jdv-Bx@gf?HiSf5?2`J7$a`z$C( z0QxQa%R-EfTt6XZ5WRMav}DR#hH)QXq|lKkPCMCyB{;xas5rI${=%Z;m9|>pTT56* zn93)V_Kh&C5QF`jazi!;hRgeyLL}Fre#yE5B(YC$rHCrOSK7j&QA`Y%QfQ}AAQ)nM zQF^fEmasy>F}SB}Y@r3AU1s~Kue>0#gu=l|q3v3-c&`K^9^yuhJH(!!mkZ{~v6F^o z+V>1F@V*-JjlcM~7!OR*!TvZ%B#}2|IMA4!1oyrga?F3?r58r|b!E`NZkhliU*_l< za5Iz`3ufLdjWh-%KK7KXU8%Y6{S`~Pgd}JWbCw6Dk)0Q0+Rs^0R`B&WvBwZS^p5E` zD}r?_6{{$6t;H*-*&WMg{o!@9c!6o5nDk8G-7v0}GP80-uo31Gjk@|`tuj*vU1RMw z4X)7UqxcCv)8xX&H`33)ve@UQ7*j|=wo8HrN5R|ZBTaJ|0%QBz@$P6NnYApqMB%2x zyYd3&A$+bqRGjxiHxCS0;8ySCQDBppFDmUO#^B0fFj(2je`q)q$6Z`q?sP_M10^VC zKGh9|I<`3Kr6nJiMO`r%@9+LbQA_O0`P5Uk`!L5`^?pWD9k2NKcDN}T!%?Y2V{xDt zuW=*piGWBUrK(!c%huGYnY9&scS_Q0*RPmIitV0PwTevnoZJX9Y>~m>zpt$yhZr}9 z8Zv*h&rmM)dpd}rX9$i50x@-?a+v`Eh2iXGz46`kKgY)Y#O`c=ZsJ{@ zgaU0buDQAxXn?KkmeDnkqEbFW7q?avGsE9(3A{_H&}HG49locvwnOvA%`O$mc59QF zop{L2?ydnT<~CY|N2ny8`eB?4zEu=1Lf>6xn4ougHCK=k8h*cctxhfw+>8=hK@GM8 zULgo9^sivg^x_rt_Q@F{Te++A}CtA?1Yi13x7oKOD!Z z6wAKtQp))SX4jePOV-ra?VXV(f~st>3!m%WEEy<9a{dxiRg%eFzF{Z6{%}o`Pf5U= z3_aech5vm}Nyc;(``I-o$RbOi`ul4<^Z`nq4o0T*w!p=Ll!r>_otG6UiI}pB8x(wS z?=Qr`(yU2Lagn9t>UO1y2p`I6F4Gnhut%!bj*%o5CLT6r0_c6_|*cmOf?JGrtK zmP9_n%0@4iE?(E${a)aR$GXE7#w_^;i0NE_9u09%?`iHTms z!-Ch+!I{+3*$ai9U#KKL%K-g>`jERr)Pt(#Ke}F5^Te6iF@{wrU|?UzK_yeepN(!1vqdDL;n2iDS>`jbV_6x zh`b=goP&5!N3Z^z>NP0|EFyH=%^3-kTD<}OC00E^xp|BJ-x<$8A&_h%+Vh7NIRA_| zC5K&1vH@#s`tFpJ*I7T+nUY+02km6vZWEpF8Cl8t+faPdo_cc^FwfYatt(BM#y3RK zB|T@qX+~BAyr^cUYmG%7eKYXfpE-5r_6tk|M2V1sOPW*?AjW^)dx-E%%u*uTK3*tU zw24*-$H}pGo*Et%rhXnu>L^N*1$bd-!r%s^5+=;dJ&;Vg|9g zvw!MG*G(&ZVTo2@81=@2PyrdNfryS`9%Mbe~gFnq)i*L=@gTEMnAg z<}TkM<K!+KcRn3$~ZyDKWGHJWvtpMK*mXQ`9fL0Qegiz zohJ9odSxA!jSO(AmD&_}4MsP%W&2I^C7>xmnPGx@Q?|XhcF4M^UYl#6opR@PK?tZ) znd9y+a>u_|NWJy&*b9ot+#GYxr%@mm&!O$MyIq~JuH1-s?A1P;gSrC2gtc8^kUq#0 zY-fSTBOEXvg*~3)>fRTQmwXQt{_w(DoTLdLlVi3gFpG>U=EYGo~R2aE*N;&MBeyQq5u%>Y+PK7Vlc z_%jOC6$42sWF9cH0;OE9_n>T1nRrhgWf1+Tpw$r~CCgw3wtR$gxo|&uSxFG|y9gc` z4?ljnMfQM2Ek!F9frZ;DTqqow^7*nA;^esblSD`ShLgeT(to=(Q{@4c@DafKxP?+t zp=2Ll9-d>*-M#|IkGN~tiX%7T!?B!(3tWL;Smk5mI7zof2%d2rmw7s;%KeVR)c*b5 z{h}h(cypG--kg#b(OqCDVeliea6c~j-|kUN`~H1qW4 zwVqyPcX(i>PzlaYsxF+@rUek3VyWGc+XeKgQ_aoPK1?P$+-a$YgRR-OJL9`6Co;-`*(qf`{hz0^(NR06B zo+|60&YN5&tfPK&Pe2OGgHkI#W)REI%7Azy=k)-HAyb`ne3OHN!vU3UMNUD4fLyD1}0qv&KC(ECh= z=3lW8(&XkD*@^B0Ax!>l+oWp9a0ARchXalg_5O`yILDiMbY#7C9i#^9CoJ6c_N|5e zQ;m|Pgr2oFrH{wmk(#_03WP<~g}oLr2_rw7F7AWEzv1KXNQ&1fcGSGC(nQN770 zBU^=X&~G9xrV*3#(0fd-HzOSo;j}x{g)7H5D1hCaagJ&%)pg6S|Zj(v*Yj ze?c3UoLc?E^E>!z2q;UGXI&zLT-K#@Sz11M7i2phg=GhW!fQz?bsFFbzp=R*pr^;j z{xnO}#(pmUuzY@&cjlS#CJs%0jk@vcTa(}>JpCr^&l_n&^RdWUZzr3CY<_5+J*kpf zwzsxR8eg1`F9a0ovI>5d8G)VJLoKR1^Iz+kvIj;DoqAAguX3=u zLq3ApUyL(aXn4oWcb7CTrLbKQ(O9?%B7B9@w*18r{VjtvPT`Ig(@7YQY zK_dil!%>hMMtu#a?U@ns)IR$CZy1Alf#4#=MUqX&%gB(YrIS$kE23i)H?c3l8(Rvk6`0aJo0Fc~5jRwc#UTnF~*nieuhYkU|96;4;O#%^|OB!24%=z+bqJY|^c zrFiNP$Bo3Hmd@ns51wgUrELiLwaSzS-kdFu)~EOWd)<5Hts8Ac^FPtwY>B?)PXobT z3@hEAp} zN~7tfyD-zQ45Jwje^!(1XO6&XGd+`@u_5Hha=Cx)8r#|i!%rIo1#Ca$+~nhyse}2{ z_hQbiR0j(U?~!)SO40`&8V%2*@@G^Od4SvVK%VKU#joOIen@UCmadr;l((h>O_{rD zq|}PNjvzX%W+qfV!bcCd7Eyt*Bsd(6end!kYfE3^5Emc<`qs(WW6E{ zlh}c8qa^c-PJrlC@Q0Z4(ic_MXLD*hsSiv4b1)f2XRrtx!)HivoEjj-5sqK z)zq8fZzal_%GP2swi#MG*>vlz7dv;In4Vj_I&G{ z5UY@76Pp!fmFy6@9D_)EIZ!ipy2Ee_nyDLQHF`y4o`^COV0&Ut5mwv{f4x$Xdgt+~ z8_L@^?FeV>25Y_(rrj32cr;ck7RjNnap~u*qe@)SObzGnUpd1oYoTS-kyD@TTec)- zFAqf8xUEM0^p&W)?*n8=I#Hmv)n6@H&;&j~C&^lH^dS0=xun0AG8Vq_5v$s7^xC+& zbE+{Z$7zYez!{@a?^I?R%T8b4oSrZtuLrgM8la%MV;_CexT=#+hW@D{Dc}WY6VAAQ z+!rm{Q^9m4Msjo~#)&!0LDj{VV`7B;g~pyaC(>_GI@hNzrP_pDmOlOp)`k`(kr54_ z(ODJMtxQTESS$!&Tjn?zX?k*&=)vhOclIIWv+&w(`@ECx7OK$j|9)Wh#7&%d z_H7mGuR}oeSY!n${a3i>9NS{sBN4E_H7jc5B5AEQw~ftdd`nJEI;4<%MjFjAhvEsB zxT;Y?BG4T;2u~|@LyJLZ$2RHq5LFyQz-LO1LPjlaIxDe_w75|3z`znKb;w5uDYYO2dl&PTlv)YEF)a6Psu!`HqM z%ODzoR0}$gg#lJI~{Hkjz28Yq-4wzra6F z26=-P`0eymJ47f_7NBw=&k%t3*F;y|(JwJ&cQxvO&5`K`&x$46ray`sU6aq+s znEG8dSj_AM3m66RBmuPpk2E4yp{&{ce|!7xw!Rp(Yqg-2)c`@`M^$#*9^3l%lZdDQ z1#2)S&k~lKWEVL8z51RPMMEG=05i$qV1;VIN900e#QRLEE8g>>s=wRXmuQWT zo^K~=ivbNXm@;&Bd_8V|!#0EgUmxYh(B1P9U6m(XRjC1`E8~Tm?Bc4c6<%0}7mGX) zBu7?Q3#Klt53v5S!YW%H?$6X>CdpC@qUi!14K#4oKrbhf*Lb9E&*L#$$sM!@&!tf_ z{@Pb^o{u28pKOg0y^^HjcAyVM_cM*rd!W|g)ZFiSi*hquAXQtYGoNc9BUnFEbZBA@ zJ9zdF4IUr~HQ|C+Hxq3%-1V)TJ;$m2`oK$rJWi`bV^PE?JdC9%jVJ>em4JA)adMDt-X_43;lIC>prn$!erS3~&sC zo*NBa4*=v6Y}CM5WQF%kEgCfAMw(4xEoW1wzHFY{?#DayqFfjp`|uh&kg`fQGyKcw z0Sv<0(-;>)Bmed!!)~Ob%IcYpChJZrR;Hu~BqeS2zr3?D8%v{?NCllIDg<8Gl;Eqr zUsOV8tfbJ5F*$%ai)`9sLQedC2*xY$x=!niOW3aJ-p2YvoV~=EK%_G(9cK0+Kbe`E zSmRIeqc4RoL}pN|Nrj&g!W0ASX5bARsAUjls|F+s4EYbdu$Yv3T20rqt(U_uu;AVxX&?*vV})SVIBws*YBl=A3^FJF;QS%${od7wLMNZ*!bNw}<;tVytedAd^#NdFBRvGXX_;)2x_+0o+$+?N?+!_| zq7u$D-Yo;AeUT80MAy$HW>J@*mjcYT^cPM^CEn*N8IL*@CvU0?4M$k8M7~E#bOib*EXNj|YRpqd zW7vg;B4d06TOPt1z=!uyf`F@DaYQ~~AJlZRGU=4arwNb-7VZhVP z!wb2v(Zn}XH~&icPKq$TEo$L_!-YN8{1R+gIeg+vjkBn2H~8%mM>j4HceoY4NZJ2{ z9P`B$s}N~_4!-)fhG@3pDZQaY;9 z{Ig^jBZk35R{0fMK^w5Y(ec%&i2u6z*kVU$_-#hHD|QLvu~&pJB@R%Qs905v4>}$j z_QEq@{sHyF$>RU`P+TaEjFjUB;m$Fb(N1mi*73(9lBvw0Z3#tF*aTK*du^qpri1C{ zu{Ziydmv@lbk7MO^DL&Cj@>4KxA1s%OcpP&1G7Z#ra=kvHtJ(a%&8>{EGEE;B#h** z5nYd6d8~U+`Ou3_YraGoPm?e7rKOHSk;RL>-V6C$xwjvg~w(M!_ zE3+*(`;&fln?U^*YLQ?caul5WBT@9ZM+o_GRuARb+jjV26eT_18aD>u+-z-iT6hbg z$tmcUVC{g!vF#kd)z>|!I_2o9ClUFSoLb-$3)@^L7eHtIP0S z;)>g}nG&a>4;%i;XPJFi;Eu&dB4hh zt(6AhFT-!i?To+JEAL*Y*Gdf1`3u9#fNCK?eVOhH2_)TyNm^2Z$37)9+p0Ca;Sh!J z>6Y&~1Y3ex^J4r3zAEpAsNGO{4JgItDsxx7@r|C*B8C#s5F7;h$k!4 z4G0K3)l7-uAEZ0R}7i-8`B0vjzKNKIcV-l`9jeXQnu zB(vP)(MCog1zWQp&0DUv={0sTjHMcH8nJ~Fl|QNT1-iGS==7+lY$Dhm1gPxfO^&aq zmfEd`)a(9I4w;7$=V+w~inj;kYl)r9%O-mU4#Js|;iy9(y};R*0Ib#9-Pw<^z7Ooq z+Xl}JMi*Df_=sbVk)1|oacp|(E?^1$mJB+`Gc?3#$Na3%%Y{VyAfwb-M<-5I2^@X2 zuX4JSUPWDd=%j_Hf$ZUxcuxfz$gCLfcZ;e!hnzW=d^uK8*;pS6*!jx}b!SdAW+R}K znFk3vs&&IH{OZfFq>G%Bt^HVtGB>PPe0>bVZ*4tNk zxy`k&)8YX3fzAwF*Rz`7bOmp&U*Z-aiDW?)gY&S?>!92 zQ4nk@M*pniDo_)-m;JR0M;*u4yrIMKXPH*H< z*ny2l;nw1plH`n)HbPKe zzk}ppX!SNw*{=|1Zu;z(k=FxEQ>!J7mQ;t?kd-gy0Ug6+>RvI& z+2utn$Ur!KYJ^649C-W+r5kJdBf44pDwS7T!yKYS%K`K$XKpmB)B~R82nfCnw6ka{ zdk9#iB8xyzoK0uEldZ4Mx{In+Aw)_oA2-wtQ}AVL6KlX;Ho9G`h&Qn*9njPgv>Zqs zlLk(Veg;{Z6u*5hP5)fZZ?NVL9(A{`dK9!66acDzXz@^ox#S-#f)_P#vAh_>M+;7nFloSkW^Ju?7Uh752TQ zD;yxU-R~S&Cj#|*sxQqoy5A&naYQ1t@9w|$?129uFGx+o`l$P-@5{Z;3E4v?q?uC1 zPU^~jS@dK2n)#(#3OlpQF8w)*Cd(Yl)F!AgWVO@4Yryv2)r2owz(Q$yX-q%a6G6EA zcBr0RLhpCh2jpqb&F3?> zjVCbMdgmzS9^=FiAN=6;LTRkMxE{R`%lxI89ZP$+i_5qXLQ+s>gcOG6Rzy-#C{9GX zV&OY2Wf?aKJ6fGcR(QCAA`6qOFi00Rr$vd=4>KFTN!Tld%hS;jYVB;1uQ@-VP-GYD zo+i5}*or-v&F}x@h9kH7!V$6HOG;MNz@dZ>perjTm!KyR?;vv_ZWOa@U@4biI`i_9 zK~vsMaXmv_y(ZPZ{?7OO1}pct`t2lZ@l7AK;$Q~s-bG3L0D3AXE%Zf6GGNuMiJ?d!FEbC zUX-0IntRKH_GPj-?^uMqWFNc(CIAutSpVjnGOrQIx|sDNyk&Q~eunpC%z(Ubd#hq3hC{ z-i`-tAh3|oos{2|H_5A*4AJk?^#TDZSJB(#wt3A4-}UhgO86vb%KK|WGlhMqVVPBx z^ve1d7^E;mEhp~Zo>3r$=+e@|H1$gQ7nfeS?q#G^cusU-w0b;%jh3r?eWWb`yeGN0 zG;)NCS?8SZfTLvMoIq3f+8$AZO`UoKh8rkdJ2L_<02T*(zeDcoXRq}6=L$DcUWVNe zY)7*%x++___>Wpe)}Orh{X+VZ0#_=tBZ)F|Xjx)zJSe1dZVCQHJw)E(tv}M7?s>sHgaO_Cj`VXkRhnN<9$lducp`=`6h#;S_fx75GexIDmoah+j^ zlB0yDZt(Uo@LdLYwj<$SVrIBk;FtXW$yyyjxx*suZxWr{nTB2m>M<$3^}hy>zzLX4 zPQ^6z2*Q&f6f7z0t*i*r|Cz|i1Pd^CE{(lzx8N{#p+lQjX>!06xHl`GW`J8VJ~SH^ zPSh>US4r$msIAiVa9bitdUWBQPZa@wiwkUk>_+pvO3<8t@v20qTSdR|l_Q0RK_;9#&YQCLxze( zeQ>_#UuVl(iCfjk9s-AV^hfa3cz%qEY4^;a5;B*yd(8Kjr-bV7z+QpSk8%EV+M7!o zJSN{=p2$m8O@04<;CFgTtt-8jlePFlk0P_vKSdoZ`)-&=5SR8x&*+2tD22T*c$NU4 z+W@&lf|XqFoFhsYbdEC-T+`B;fzL_kw|9R74vBA*3+HFk6*U4Fj%VAYozZ_lLnE)` zUej^t&#Rh%=zT<;Cc3*w0>&zPHgR*?maa5zjPu*_^rr53K6kgIrvn}=0vO#`vSU*u9v%466eK7pw731)?Egy@tIV|C5VCwVZ}w{%*kcr@*6mhE#V>v zV!6vc@HrUyybcaBOGFUT^w%$1N~0}|>>j*9*;HFf5ih<&$#Q1QkCos}bD0SpqjK}( z%(eF<>jIIlITs1gxSsKR-_#d=bnAiFNoAXCFStm~+AvAKS`fMz$M=))aRyve?W@+2 zSf)~ED@dq1FN+0mTl*5$%bncIp7Er1YKSwRoaCNJfDIjy3W!WGSZj|;$ayS$xz(wi zCjqwKbs%f@Cw@17oyUP#YPPFS=LWxkLVid}7-LD2bPSSS^+!ttu?cxmoQ?D|6kY&a z=mo>c3Vk&v5ZSJQWR!vNK$JnJNkZRluX_XjQF-gR7I`fRx{e#n0N4j`3~lbd*bW7Y z)?kxRI(9~#Db(cYbnum*NOXr;f^o{r{1v`J@r6$K9^f2D`OGWspX4HLlUT{ z$ds?DMx4-oW`d+{@AeHxGjWt%SlM{EAAHvam<1fc42D?= zv6#fiB?Iy&;ps5^gNv>L)dg!TkvtXKMV>0YO{sw#b?Gd@BOXw%)qPY?nP1J%QW^ZU=;tpHUK9hIAMgnH`m=Y8Gi}diSn@8mI1@Iqv*;d zN(hpQsrOzS`52x~5WnmOuif!Ctzg(a$r%>gL*u$o-KOXJz!CSsdY20T3r7 zPMhc_VzT>RD5~l1+i$*avRp^tSOzN?l994>ft>E%Ur!hfsN}%|e%PO0}@4x`UiCfcM zJ;4OCHm&g1OXjPBUY=-i9ci;PF~@uC${H=q53BipY=MlUg(1lbKaQZ4TEtaHB=%O~RgBw3xru#GA%-_ceoVD1>7f7m0K@UXXYB~4E;$+!_)ypUH3>1azdI!tvbn>sJ9r*sP zVsD%L;d`Qy7l`}}oRWIHQengHZo2~N*Wm~(2tLou312Gh@<3Z~P`YcyIicNOHuH-VB(uiStHPbO+(EZX$qK&OY=zCk3T%Ts9Imxuzozl#(De(zqqKiONP9 u{gzu<_1;wsUQ9$|1VZE?QXN*0Z#OMu+eDgkm`#Ca2-hL}FSz~R%lr@fTw_N7 literal 0 HcmV?d00001 From 4a8651ab39bbe45293e4830da0a457f0fd4b7e73 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:58:02 +0000 Subject: [PATCH 050/167] Add webp test cases for upload/view and preview Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- tests/e2e/Services/Storage/StorageBase.php | 105 +++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index 6879645a22..8b7ceef45f 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -869,6 +869,111 @@ trait StorageBase return $data; } + /** + * @depends testCreateBucketFile + */ + public function testUploadWebpImage(): array + { + /** + * Test for SUCCESS - Upload and view webp image + */ + $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket Webp', + 'fileSecurity' => true, + 'maximumFileSize' => 2000000, //2MB + 'allowedFileExtensions' => ['webp'], + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $this->assertEquals(201, $bucket['headers']['status-code']); + $this->assertNotEmpty($bucket['body']['$id']); + + $bucketId = $bucket['body']['$id']; + + // Upload webp file + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.webp'), 'image/webp', 'logo.webp'), + 'permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $this->assertEquals(201, $file['headers']['status-code']); + $this->assertNotEmpty($file['body']['$id']); + $this->assertEquals('logo.webp', $file['body']['name']); + $this->assertEquals('image/webp', $file['body']['mimeType']); + + $fileId = $file['body']['$id']; + + // View webp file + $view = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $view['headers']['status-code']); + $this->assertEquals('image/webp', $view['headers']['content-type']); + $this->assertNotEmpty($view['body']); + + return ['bucketId' => $bucketId, 'fileId' => $fileId]; + } + + /** + * @depends testCreateBucketFile + */ + public function testPreviewNonWebpAsWebp(array $data): array + { + $bucketId = $data['bucketId']; + + // Upload a PNG image + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $this->assertEquals(201, $file['headers']['status-code']); + $this->assertNotEmpty($file['body']['$id']); + + $fileId = $file['body']['$id']; + + // Preview PNG as webp + $preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'width' => 300, + 'height' => 300, + 'output' => 'webp', + ]); + + $this->assertEquals(200, $preview['headers']['status-code']); + $this->assertEquals('image/webp', $preview['headers']['content-type']); + $this->assertNotEmpty($preview['body']); + + return $data; + } + /** * @depends testUpdateBucketFile */ From d1511d5ba1734a0839100c6edfd17107e49095cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 22:26:30 +0000 Subject: [PATCH 051/167] Refactor webp tests per review feedback Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- tests/e2e/Services/Storage/StorageBase.php | 120 +++++++-------------- tests/resources/logo-after.webp | Bin 0 -> 6236 bytes tests/resources/logo.webp | Bin 17200 -> 0 bytes 3 files changed, 36 insertions(+), 84 deletions(-) create mode 100644 tests/resources/logo-after.webp delete mode 100644 tests/resources/logo.webp diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index 8b7ceef45f..2012be7375 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -30,7 +30,7 @@ trait StorageBase 'name' => 'Test Bucket', 'fileSecurity' => true, 'maximumFileSize' => 2000000, //2MB - 'allowedFileExtensions' => ['jpg', 'png', 'jfif'], + 'allowedFileExtensions' => ['jpg', 'png', 'jfif', 'webp'], 'permissions' => [ Permission::read(Role::any()), Permission::create(Role::any()), @@ -263,7 +263,39 @@ trait StorageBase $this->assertEquals(400, $res['headers']['status-code']); $this->assertEquals(Exception::STORAGE_INVALID_APPWRITE_ID, $res['body']['type']); - return ['bucketId' => $bucketId, 'fileId' => $file['body']['$id'], 'largeFileId' => $largeFile['body']['$id'], 'largeBucketId' => $bucket2['body']['$id']]; + /** + * Test for SUCCESS - Upload and view webp image + */ + $webpFile = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo-after.webp'), 'image/webp', 'logo-after.webp'), + 'permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $this->assertEquals(201, $webpFile['headers']['status-code']); + $this->assertNotEmpty($webpFile['body']['$id']); + $this->assertEquals('logo-after.webp', $webpFile['body']['name']); + $this->assertEquals('image/webp', $webpFile['body']['mimeType']); + + $webpFileId = $webpFile['body']['$id']; + + // View webp file + $webpView = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $webpFileId . '/view', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $webpView['headers']['status-code']); + $this->assertEquals('image/webp', $webpView['headers']['content-type']); + $this->assertNotEmpty($webpView['body']); + + return ['bucketId' => $bucketId, 'fileId' => $file['body']['$id'], 'largeFileId' => $largeFile['body']['$id'], 'largeBucketId' => $bucket2['body']['$id'], 'webpFileId' => $webpFileId]; } public function testCreateBucketFileZstdCompression(): array @@ -872,90 +904,10 @@ trait StorageBase /** * @depends testCreateBucketFile */ - public function testUploadWebpImage(): array - { - /** - * Test for SUCCESS - Upload and view webp image - */ - $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'bucketId' => ID::unique(), - 'name' => 'Test Bucket Webp', - 'fileSecurity' => true, - 'maximumFileSize' => 2000000, //2MB - 'allowedFileExtensions' => ['webp'], - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - ]); - $this->assertEquals(201, $bucket['headers']['status-code']); - $this->assertNotEmpty($bucket['body']['$id']); - - $bucketId = $bucket['body']['$id']; - - // Upload webp file - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ - 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.webp'), 'image/webp', 'logo.webp'), - 'permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - ]); - $this->assertEquals(201, $file['headers']['status-code']); - $this->assertNotEmpty($file['body']['$id']); - $this->assertEquals('logo.webp', $file['body']['name']); - $this->assertEquals('image/webp', $file['body']['mimeType']); - - $fileId = $file['body']['$id']; - - // View webp file - $view = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $view['headers']['status-code']); - $this->assertEquals('image/webp', $view['headers']['content-type']); - $this->assertNotEmpty($view['body']); - - return ['bucketId' => $bucketId, 'fileId' => $fileId]; - } - - /** - * @depends testCreateBucketFile - */ - public function testPreviewNonWebpAsWebp(array $data): array + public function testFilePreview(array $data): array { $bucketId = $data['bucketId']; - - // Upload a PNG image - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ - 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), - 'permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - ]); - $this->assertEquals(201, $file['headers']['status-code']); - $this->assertNotEmpty($file['body']['$id']); - - $fileId = $file['body']['$id']; + $fileId = $data['fileId']; // Preview PNG as webp $preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ diff --git a/tests/resources/logo-after.webp b/tests/resources/logo-after.webp new file mode 100644 index 0000000000000000000000000000000000000000..b91c5dc1fa912333d58fba3f42bbce0f8559ae73 GIT binary patch literal 6236 zcmV-i7^CM>Nk&Fg7ytlQMM6+kP&il$0000G0000R0RS5T06|PpNO=PQ00DPkrfu8c z+?{(zqY)AFN2O!~Qf%9L-sV}AW&o8cNKg?nl#D!qHi47@gh@=y2@{Kh-oI@8%iSm= z=)qOPaQVyk-FttlfQbIXaU;o*RAumlUok6QU?KLAY1z*WDYJdvkuraL+EC)LpY){Y zp44T`{_)M63}nm~zujp~h_?(y%x}NDle!G=(pTYq8VWqhn3Il#8<(}yhJy3&nJ6#^ z0cO*aqI*)Kzj1jC`OBF1?;5#E`0Yh@Qm3{EeP)Z%ATDDuI{Y^-Hw5(OKQ{zYbWa*W zWPRE4)ywR(Mt$QHgy4&NNeC?o^Z74WNn-gc`NzFH4YD$pr^9NAN>ZKw5cH(zp45p9 z!+@`h3PP}-se%xEaSsTI0pTiRkPwi`U&%l2O4vRMJSQC{1630K{D-E;W3Wns8=e72 z85M+JKT`!E`0XAEVB@fbZ}1Sn8jBa`H!ea5K+7194yI9oJpVE2VH>5AfW~EjTSf&T z*w2x_lD|FvPHJGrXA4#SO1{lJ{|Z8Ion(xJ5Nys|3kPaQLFmD7cpnj!?4mG$;RDLQ zVM6eH2Eq`AF$fc!f1iNRhhc<5WrbjwQ%N}?ST$5~sq?Z0he`@TA}0jP<4Uf|-(-8( zuvJl&+*}{6s_7%4Re2@lylfFu$$nK;a<=rVm&cV{=Df+)sHm4MpX7XjVbxH{RryCkRmDj)RkE>0TFJ2-7VwXR zmdKS{k-y2NhR0g?*)}Pa+%;43kN*0kk1cl_UaiT=C?n(ZQqpxJn`4IZ@x42L6-Lg>aNYV%KVo0 z*0%qW-$gV%kN+#~pXT49k1%i25BHvxUc-NHy+D4x{;zw!|E~3i{Cz;oPAk8#Q)djXX;=3|LQ&gKb!w$|Be0Q{9nH}uMghOV{h1UE8({~D`f1KdC<|! zu@p<#0Il+OXzV-|r{v=OY@L$tCmix-^oj3w>7KRRgK*mP;&o7o?46SCAuCw`6W}r^ zB3%p~hco$lxECtRZ~3ITYrOH;kD|6s{gWfFWtygWT%s#?#&;;3W1~}+w(}W^j z=S5IwW#IT3ve0SKO1BW(iepf+T3)toYU81!P7sNAoeq(sak3(m=Ft9V#*wK(>V^*PqOsdx20%Y$hAl$z(9x#|M7z$1 zD2p{9CtsrME?hlHye*<)8LXoEGn+mTcJmzPQrCIou^&Zh{8^xSTSe%f&BH+)Op<$^ z_TQC5U=KU#|JvB*aZ?i=hTQ0Kh_g}x9@5iD>~&G<-R))6N#LrW)b?BcE(;s7TKsWs~mMO+YdtEM+g5n zl2)`|GA=#ux!Ofu1=$J8$Rb4bek{;EEuQZ2S-gp@ld@gsLzH5~i`?vE*#7^20GC%8eI9U= z@%?N?MIezsghZn_y=QC`@7kZ%CTtda@I`i=8#HhnJ#_$7!xVV&Gp+PYvC&vbLNzLD2WJpe2J{FIlAA+0T^ zxX|v^e_aHH{}`(w?~8|`8Tb}hGdYIZSM3?t4MCG%{PbQUc8q%wMJaYMI<=Z)EkccW z*N<(D-}J}%vGv35WagA{X7MPbnZ>Z0)AMTfMJ+rr&hLjeA2gr0lh z{*zjFHP#@ZQ#()!%w1=UiabUR9T0TJ@ltvap^6$8(4;lmw7eSj7EQ?xoDd02M% zb2N+u#9AqMoYZ-zwMDd|1qWI}6S?>0L0T-Y+uxnKmCvAKEA`3KVGD{~aZ)Gg4phtR zYkGs!Nsi&-vd*(T)CRB^Bj|nBcwSD2b0Tq0*6jGv-e|j4y|fjM!5F8^<2ooNo#r2J zW+xT{G#Z>Df05cTB@f&rbzRf168Ubp^^F8(%~k5%f*M{4g(oZUUv_^CgMx)|zu~)v zN!obbh7KGoTVz;b><+65Pu}x7{Cn?QLeMzpA^>|RU9E`hf@f*4={F=nqP0dv2O?$}yt0ygxkt)zJ6gQFM$4S9$ zxY~T=k%$8!bNM0ea{ZJ+mua;SK-fiWnv6T|Kwx((FYbUG9v>M;Sc=aH_L|Gd4*xj3imzO2slyD z7e8dNeq%{gF5oN^2Iq^gdlMfhm`5e%gd((A1bO$nN}7A=PMqYK{TI6beu7AMS@a4( z*6f}oceOHm3s!`lPYc&^@r_Y^-G}gGdgV5}mO@?PsqHexdlN0<9ROo;`o4@m{|4s%sC=R+(M zhfoL@Me>7I2uFYa93K{Xh0oPG!HNCnPxnPEP;ggvY0*@_Ydl z3Io2EL@{)XXz%qPe3p$IT}c2^$ZUFMuXGtudL>V&%Pp&aj~0VWgAwcY_&lnzeUrrS zE;X0yNAcJF*`AJD!7f^Yg1AN^nBE`X8g3#wu4uBDj>XJKYUGK8VIza_ikdSsZci-! z>|Ju|7J)2LI;N=wvimZz^r^| zgW2EU)NiJs{K8(M#M0*fsUp2xcTVHCmn8z@k^7|Y|Kb^IMbL0AG;mAkAV7}jJ_OJP z{A$Q7{u~6AIz~6W!Fj)UBJcu0|NCmrlPJrxWLeg4NpG=V07_*i*ZtKQ668oVl|;16 zAeLT#r}Z6G*ufnpouQg){`O(wS9@}9W$82XS1)!!a4d?ck1bHRy%Rhhq1PNZd62RF zK?z3+q7`)UkGllyt^?7HwgbS~KMO9_Uqi$^uhn!jWjS-u+w25WqAj3H3EgJ;LEodU zKU{1|?KeH*Hs43sVr&BOVy6D(adsZrTq zKGJMNV>c8ER|-77k|tx2j!&j4T7q&|HyU;C^+b^(ao%H>$l9dUirByx9P2Ou+45S3 zzFDpQPu}?^vC3&&LP={Pl?6x|#Ae668Vf<{lZTWPpC4@rnYajhX~*t6PC8L6ny})P z4I`+2T=ASU2f}gXZ7oZ5>@aZQV%s9a7hrW*MUsE4wrk|)uETbe;%QcP?rs{+_qV|3irS#;V-0$P$bS4bOs z#D*aqFbH|`!#V8Cn0y%e`KHOI!$d6Wyn>}Zpe7Tnwq%}_y(#YI6Rj#=+Tb(hKFji= z6E$)3q+U(1@%a?5^aOl<9T(e=V#cknjK7irWJ(bWn22l~tYXnF7+vVM%22RPz|W8( zsylO$h24CS=sxfW8JQ|-oH3`L0{kYE5!QkeAXQcMTOE)}{o#A!AVM46@zwhVAM2_? z7Qh44f45o047Tv#D06v8W}Z$a%;x3mUMVva&@xk-ep!$I@il+{6kGrQ6K!RNF2L%r zisb)UY}d)pT~o%d#~OpCotl#i{@n^D4i3WSn2?Wq+FM#}1&g3lxN%aP=E)smY#`6f zv#6w5pq#;zb&led+f)1H^X(2`SC1d47CeH6&{wRiI3?SZrrgpLqPr+HG|#otJb3ur zv<0#OLc7 zLKdLLjCZs&$UH%^E_g!xENUA8+D@f$Z?gf-QIT(JSg9{+R?NJlfB{T~d7gB2bFLtgiW0rTaCI zC^&d?>t=8d)~EjrQ+lU135SYtIU7z@9S)bl*0k9PwIjUG&TLo@v_KK&C^Wdm*CQ{Hc@J#EeCz74@p}+Z%krc{FtJENESs96hf}r zQi}mhVXRA%dl;S)44z_Hc@g2GNkn;f7;eCoy>%7d@)@qp^mkbmSBeIGPyF+fl9f<; z^cGCZ!Stq~88X-*T1ASdj_>!{N4*nzh=w~A0S^SO+h9sNgUG40+q$vkquyYzlQV~Db1m6v9HI$lZ+M{m)`h@#B z=n{8|O>27W9Y31|L;8PC_qZZKHldtkr%nHxwxL1NPHg^g6iTTU9aYakFRrnckxIEO zXk-^ZE3Se&L)Zb8)b9V)O&*A+2$$uYzhx{3;RaYJ;3>(I3%DRRu=zMh$j@onhgWCT zmj?IcNC!&V;(Ym&v@~fa#fTUiMDsD!dx2(A#fQY?!l(x={2@ld%n+dzmnnp9$y!QL zZU(Y8MWeHZ7l>!`=rC-1`1t5Zj|?C`eVu>)$$9PeijsbcueiD0!~*KkycDn>yMOgu zY^|V{pr9UB@`bgKkiSqMwYCFBgUKn(Lzt1%FvAEsUeF!XqR-LsfEBJ>dhmL50QjKX zl+M$gsTA2aXjJW^?XO@S;r7D-SW|Z#_F&b3|An-gY*lNb%DaUtXbUplIOdcY%C6cto+5^!mRhQ2E$tkrIr(j%tx)AG97;_8t;9 zutw--y6f&ZfRK&i)huO3 zR?tuumnt047liVwBkNt;3Lr-R`HKzKY1$I7DZUC%_iE6+D{v~W=FEWoV>FU)P< zfuy7b37?)*I0~<_anKBKpGnaiDq-NX2{D8um#&|1P<8X8M&WdccG&;P9Pyko!s G0000WrY4pE literal 0 HcmV?d00001 diff --git a/tests/resources/logo.webp b/tests/resources/logo.webp deleted file mode 100644 index f9bde111dbbd3ff06345f7fa53a29c2013d42f9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17200 zcmeHtQ*bU^vu14Dwr$(Vj&1GOwr$(CZSQ!;wr#!1eCJHnslR5X=IY$c)ZbTK>!Pc> z*IM0ALs?ovf=Uz!NJCsiNnMGH2=5>M?gKa%n5F@&0ZiZ*RkB2JQDGqoDix9g477#a zmjm~~oPe?QvApKb%kH7SEg#Y04}~A-SN>J~>)f_t9<1U^{jEWPKc#@VJNlZzqrizD zeoyw(?tTB3;JE+w_urp?Xlw2{|Kx|gzZ^jMUH*OgCD>tquK50QXK>0y6a!F04Sz zTzM-ipi`Iref)2q{QE)tfBPHqzatrB7U9f=G(j_IM;KD~V3G7B#p;o|+*KrqU}8Bg z@y_>2S9r@fEMPA(8Lp2>xXNYK=I^D%B=Yo$UH&CF5E6mygd6c?%_GWx_~sE0`Ajmsfvw)!**n8I>){kE7XWQrX%O(s+B zHLoo2PUpQnZFsl?KOhlt5@aTjy8_uyRNI8oPxb~QjSV8cCyRfX8HUXOc2zs6N=O1C zKb6}eeM*UA99gqVs>rIQ&G=%JWf&TRL}s+3+rL+dzwPWe6lyzOs0SUq^!F!bQa(75 zfF!8?G?VyXSX-HEgbZIMdaOtlH@c8p=7FM~Ag`X5?0I;H7-tx6WR8Wmb=@|kyYrwN z!+xk?tj`=B{0G)EI~I3EKJkDw*^a6599>x4|69l?kfy+X-~pVKd(A7E`6}9zE+aMB_@m}VyUV-{-kBq`Np-=F>0=D`F2@xt zpJp{Tg1{P?UNdOg<1KGH94rz~_(W+4b88!I(y&`izKS9}E5xCxtU5o+9(sn&4;5uJ zGA3xm`YsF}K8!(V%oW7)3zSI+zF>RD0_cZ`tU3II#RG}3|TC&WC97_h#Kw)(~E@QNxixO&Hw~`>(vw&xF@R}?p3}fjpgmy(=n&OnX zu~uAdO^KLUY!r2+yPuHpa-kcSi?IU;S+mRt$mf7>cbTgR(yn`YOMQYiQzvY-;gq2K zFlU`Z1}ePOj+wQaq7@M;&{0o3b9eX-!$nMmXl}SR;X=#6@1mM6lYo+dDINKyESTnf zy|tB@mh6qO;*3$OFX$%Me05>h7EUWE;DNM+)HDc(=dq}>k^|mCT6CM)(pi{vhC0sT zVfxbm=7BjGrvwq0;M;=zrA&H}QNUoj`MfF794~VyL!(gapS;^s=N%k~VyBJ-NlU~# zt7_5Vp~}FjE`ypHU7A*p5@s8a^?}6PE48Avm4<3`bm>NKAco^CF}<0gQ{>ZhrMY>8?TKNOXL|xlL^?6f2 zab0R<25HOH6>CJw;mD)0l-?JiF454vZac!Q_q97|wXPRY*sHnJS*!c3_sS+@&S3sS9@%B~;qVEp4>y_&zIBFNGBrZ?s13JMsSu92)lsJ^qgn`mX~1 zce%>@BFgL;s!AtE5ny7Y>NSLx$rwmwe;`H)W?kG=>ptCNrE-7jJOy4)s~(ajeO;3#tK%L>F=|!^SY;BZ~Iq;jv#Vz{5lWVJ_9OK zm3g{QoixW)3^?(DwOte-;`OSqN?B0l+2 zGK8db#HD=84^V3ay zlJI){JvHYP8gkI`8j=^kaO^d8*t4^7A?cuy(Kb^vB{i|-vycv|&mjAXLQL%a!< z^sTIztFRZG9J1nSxX>HhuEyYS!gBSf$b66;<1><59>jm9lmB@^|Ki^vB) z#v{;|^T&(uV13l`p=Z|&Q}!1VL`W$M zW-vH^GU6XiZECE2RTx=Cw5y4?;0!|6xS*@m!hP&Sq9t9MLoQAq)1imAhD~IW02epR zKk8JjSM4hMWqSbN;q{Asck5iMY;QV*un5Jkb)wX{)F_peTbALDkB12yDTir!@}u8bHsRZ|kU zD;8OZo?S~Y8=P>}c{GuMjA%@Wg32nTaz4l7%IK8CZ?%L*^Xj+8uh)S`{7~N-T{Sf=X z?WZa1Lbs7=cMH*PyiabCPbyH~2|m}$fE9<`D)7k9IHxcXv|aH3Ca+sds- z__cY8LLIp`k{yW>iYY`qj{bSvl~!lR3M-wSQVYhv5P?(-rTGjnmu6-+gj!OK9LL~ur`+r_oInA z6^|^$0%{06new1yDN97!EJ0RQ!{W7*#>AkaA$IxCar9T z2UJd@S|`h4JDD2kPg*B9J^}j0&7*>Yl}TOX5O0S?rUo|bs750h9adW!@fmE|DGm$W zYa2%1T!wtQ+>|LcvS%=2-Cg|+@KM>B`nU8u@9`DAhTeqKn{N6jCF957^1q}iV~WH4 zAMBj`R!R5b#jcZ4*e~oR&J(q$892;;%lJ>{h3`@~`_}DYKzW)uoiUz;yK3AFsly3$ z;Lx|%y_+6ihK*kwBm!cr(*t##QrPm%K7R$uefLqoPG)?R5)<*ejz9zx*_YTPV;7)CR*pjB=TH*yUqA)5D- zqpXYvne1RdDs1#HcTLQ-1c{G3d%02v*(H^s&|d=yD4MN}4v(2;=%;4669eUk=V!6M zt^u8tFkqn0zUCKNvQz9%Ol> z=o5fS5fx_;!`(L0bGYbB3$<sj)1L6;jw1MZ``=C)lO7c4CnAQZr-+}`4Yw4y~n z)PTDwG|(6By-3EdY0}%;li!sye{}8wp_HlMkOjzUlYmRfE_N0{GuQiSqjUy{%NS5d&u5!`G(hk-oLPG(!N*D%$KL(JqlxsJzeU z{ABAg7&~{!8nF=r^;61l znNP%2<0E1&Lc@EL*6a`1O}vk#g7#FJpmt?fARk;d?$yyU0zzT0a* zJIY>DT!v%^{hgx(0Uj$+LXdwHH~b5V;S8N*AczcS=f|pneOdICMMFJnG;Q&{Bm{YV zfm3%+T<2)A4)XCwS^66&S5XByBCwtghZ zbbu2)t`#W_Ph476P<`FblM85Fx5wkfhc%%m^pDl#X#_FnZ=zB5f~ou1UgcIXK!nLnYy>iMK7rcoVJ!_q#N?eBQV0px z7(ChzoRws&xpxCc$B!>ba4Oo+wa+lftOD`i{*;ligVitNu|y4uh5bHrEqP|<$07eT zw$l=wK|Bs#FlXJ`mEz<%f8~VqObPOhU>~&yay!jquYF2GP!oQ}Vp#V_MQ#ZwwoG~N zW(!UVkA~r_Ha;QCGUtx;xs@zYMg&O~z01IV0cH&%P}L^PW~x!~tGO!d%XQ9iAEeF( zcAVe;Zqpx>4w_=iilhlV=VmO|0E z3GC>9=`s~KnYZ*+`WYW0R60S4z8eOs7#|U3Dkf@5qjOPk-@~OES}Toeg9~2Fr%|ca z!M*Bfgs+IR#sNEC4QAH?2L3ZP|e?ZRee9myb` zzP%8&3mQ9;n6!X(JI_ORKP#18r{~bXwMKbJ&K|YoDTyH$dzLU+HZ%?8Q3GeWz<;1w zv@LPNgRexYBrH>8ebSv6ITjH$ePPf5k@rZr$%kCB=%Yus_ZhAb{MA3~A%m6th$dj; zHa9XxEiw-fdm#erVC-F^Y8fRiRcK-tx|xnv=1*jdv-Bx@gf?HiSf5?2`J7$a`z$C( z0QxQa%R-EfTt6XZ5WRMav}DR#hH)QXq|lKkPCMCyB{;xas5rI${=%Z;m9|>pTT56* zn93)V_Kh&C5QF`jazi!;hRgeyLL}Fre#yE5B(YC$rHCrOSK7j&QA`Y%QfQ}AAQ)nM zQF^fEmasy>F}SB}Y@r3AU1s~Kue>0#gu=l|q3v3-c&`K^9^yuhJH(!!mkZ{~v6F^o z+V>1F@V*-JjlcM~7!OR*!TvZ%B#}2|IMA4!1oyrga?F3?r58r|b!E`NZkhliU*_l< za5Iz`3ufLdjWh-%KK7KXU8%Y6{S`~Pgd}JWbCw6Dk)0Q0+Rs^0R`B&WvBwZS^p5E` zD}r?_6{{$6t;H*-*&WMg{o!@9c!6o5nDk8G-7v0}GP80-uo31Gjk@|`tuj*vU1RMw z4X)7UqxcCv)8xX&H`33)ve@UQ7*j|=wo8HrN5R|ZBTaJ|0%QBz@$P6NnYApqMB%2x zyYd3&A$+bqRGjxiHxCS0;8ySCQDBppFDmUO#^B0fFj(2je`q)q$6Z`q?sP_M10^VC zKGh9|I<`3Kr6nJiMO`r%@9+LbQA_O0`P5Uk`!L5`^?pWD9k2NKcDN}T!%?Y2V{xDt zuW=*piGWBUrK(!c%huGYnY9&scS_Q0*RPmIitV0PwTevnoZJX9Y>~m>zpt$yhZr}9 z8Zv*h&rmM)dpd}rX9$i50x@-?a+v`Eh2iXGz46`kKgY)Y#O`c=ZsJ{@ zgaU0buDQAxXn?KkmeDnkqEbFW7q?avGsE9(3A{_H&}HG49locvwnOvA%`O$mc59QF zop{L2?ydnT<~CY|N2ny8`eB?4zEu=1Lf>6xn4ougHCK=k8h*cctxhfw+>8=hK@GM8 zULgo9^sivg^x_rt_Q@F{Te++A}CtA?1Yi13x7oKOD!Z z6wAKtQp))SX4jePOV-ra?VXV(f~st>3!m%WEEy<9a{dxiRg%eFzF{Z6{%}o`Pf5U= z3_aech5vm}Nyc;(``I-o$RbOi`ul4<^Z`nq4o0T*w!p=Ll!r>_otG6UiI}pB8x(wS z?=Qr`(yU2Lagn9t>UO1y2p`I6F4Gnhut%!bj*%o5CLT6r0_c6_|*cmOf?JGrtK zmP9_n%0@4iE?(E${a)aR$GXE7#w_^;i0NE_9u09%?`iHTms z!-Ch+!I{+3*$ai9U#KKL%K-g>`jERr)Pt(#Ke}F5^Te6iF@{wrU|?UzK_yeepN(!1vqdDL;n2iDS>`jbV_6x zh`b=goP&5!N3Z^z>NP0|EFyH=%^3-kTD<}OC00E^xp|BJ-x<$8A&_h%+Vh7NIRA_| zC5K&1vH@#s`tFpJ*I7T+nUY+02km6vZWEpF8Cl8t+faPdo_cc^FwfYatt(BM#y3RK zB|T@qX+~BAyr^cUYmG%7eKYXfpE-5r_6tk|M2V1sOPW*?AjW^)dx-E%%u*uTK3*tU zw24*-$H}pGo*Et%rhXnu>L^N*1$bd-!r%s^5+=;dJ&;Vg|9g zvw!MG*G(&ZVTo2@81=@2PyrdNfryS`9%Mbe~gFnq)i*L=@gTEMnAg z<}TkM<K!+KcRn3$~ZyDKWGHJWvtpMK*mXQ`9fL0Qegiz zohJ9odSxA!jSO(AmD&_}4MsP%W&2I^C7>xmnPGx@Q?|XhcF4M^UYl#6opR@PK?tZ) znd9y+a>u_|NWJy&*b9ot+#GYxr%@mm&!O$MyIq~JuH1-s?A1P;gSrC2gtc8^kUq#0 zY-fSTBOEXvg*~3)>fRTQmwXQt{_w(DoTLdLlVi3gFpG>U=EYGo~R2aE*N;&MBeyQq5u%>Y+PK7Vlc z_%jOC6$42sWF9cH0;OE9_n>T1nRrhgWf1+Tpw$r~CCgw3wtR$gxo|&uSxFG|y9gc` z4?ljnMfQM2Ek!F9frZ;DTqqow^7*nA;^esblSD`ShLgeT(to=(Q{@4c@DafKxP?+t zp=2Ll9-d>*-M#|IkGN~tiX%7T!?B!(3tWL;Smk5mI7zof2%d2rmw7s;%KeVR)c*b5 z{h}h(cypG--kg#b(OqCDVeliea6c~j-|kUN`~H1qW4 zwVqyPcX(i>PzlaYsxF+@rUek3VyWGc+XeKgQ_aoPK1?P$+-a$YgRR-OJL9`6Co;-`*(qf`{hz0^(NR06B zo+|60&YN5&tfPK&Pe2OGgHkI#W)REI%7Azy=k)-HAyb`ne3OHN!vU3UMNUD4fLyD1}0qv&KC(ECh= z=3lW8(&XkD*@^B0Ax!>l+oWp9a0ARchXalg_5O`yILDiMbY#7C9i#^9CoJ6c_N|5e zQ;m|Pgr2oFrH{wmk(#_03WP<~g}oLr2_rw7F7AWEzv1KXNQ&1fcGSGC(nQN770 zBU^=X&~G9xrV*3#(0fd-HzOSo;j}x{g)7H5D1hCaagJ&%)pg6S|Zj(v*Yj ze?c3UoLc?E^E>!z2q;UGXI&zLT-K#@Sz11M7i2phg=GhW!fQz?bsFFbzp=R*pr^;j z{xnO}#(pmUuzY@&cjlS#CJs%0jk@vcTa(}>JpCr^&l_n&^RdWUZzr3CY<_5+J*kpf zwzsxR8eg1`F9a0ovI>5d8G)VJLoKR1^Iz+kvIj;DoqAAguX3=u zLq3ApUyL(aXn4oWcb7CTrLbKQ(O9?%B7B9@w*18r{VjtvPT`Ig(@7YQY zK_dil!%>hMMtu#a?U@ns)IR$CZy1Alf#4#=MUqX&%gB(YrIS$kE23i)H?c3l8(Rvk6`0aJo0Fc~5jRwc#UTnF~*nieuhYkU|96;4;O#%^|OB!24%=z+bqJY|^c zrFiNP$Bo3Hmd@ns51wgUrELiLwaSzS-kdFu)~EOWd)<5Hts8Ac^FPtwY>B?)PXobT z3@hEAp} zN~7tfyD-zQ45Jwje^!(1XO6&XGd+`@u_5Hha=Cx)8r#|i!%rIo1#Ca$+~nhyse}2{ z_hQbiR0j(U?~!)SO40`&8V%2*@@G^Od4SvVK%VKU#joOIen@UCmadr;l((h>O_{rD zq|}PNjvzX%W+qfV!bcCd7Eyt*Bsd(6end!kYfE3^5Emc<`qs(WW6E{ zlh}c8qa^c-PJrlC@Q0Z4(ic_MXLD*hsSiv4b1)f2XRrtx!)HivoEjj-5sqK z)zq8fZzal_%GP2swi#MG*>vlz7dv;In4Vj_I&G{ z5UY@76Pp!fmFy6@9D_)EIZ!ipy2Ee_nyDLQHF`y4o`^COV0&Ut5mwv{f4x$Xdgt+~ z8_L@^?FeV>25Y_(rrj32cr;ck7RjNnap~u*qe@)SObzGnUpd1oYoTS-kyD@TTec)- zFAqf8xUEM0^p&W)?*n8=I#Hmv)n6@H&;&j~C&^lH^dS0=xun0AG8Vq_5v$s7^xC+& zbE+{Z$7zYez!{@a?^I?R%T8b4oSrZtuLrgM8la%MV;_CexT=#+hW@D{Dc}WY6VAAQ z+!rm{Q^9m4Msjo~#)&!0LDj{VV`7B;g~pyaC(>_GI@hNzrP_pDmOlOp)`k`(kr54_ z(ODJMtxQTESS$!&Tjn?zX?k*&=)vhOclIIWv+&w(`@ECx7OK$j|9)Wh#7&%d z_H7mGuR}oeSY!n${a3i>9NS{sBN4E_H7jc5B5AEQw~ftdd`nJEI;4<%MjFjAhvEsB zxT;Y?BG4T;2u~|@LyJLZ$2RHq5LFyQz-LO1LPjlaIxDe_w75|3z`znKb;w5uDYYO2dl&PTlv)YEF)a6Psu!`HqM z%ODzoR0}$gg#lJI~{Hkjz28Yq-4wzra6F z26=-P`0eymJ47f_7NBw=&k%t3*F;y|(JwJ&cQxvO&5`K`&x$46ray`sU6aq+s znEG8dSj_AM3m66RBmuPpk2E4yp{&{ce|!7xw!Rp(Yqg-2)c`@`M^$#*9^3l%lZdDQ z1#2)S&k~lKWEVL8z51RPMMEG=05i$qV1;VIN900e#QRLEE8g>>s=wRXmuQWT zo^K~=ivbNXm@;&Bd_8V|!#0EgUmxYh(B1P9U6m(XRjC1`E8~Tm?Bc4c6<%0}7mGX) zBu7?Q3#Klt53v5S!YW%H?$6X>CdpC@qUi!14K#4oKrbhf*Lb9E&*L#$$sM!@&!tf_ z{@Pb^o{u28pKOg0y^^HjcAyVM_cM*rd!W|g)ZFiSi*hquAXQtYGoNc9BUnFEbZBA@ zJ9zdF4IUr~HQ|C+Hxq3%-1V)TJ;$m2`oK$rJWi`bV^PE?JdC9%jVJ>em4JA)adMDt-X_43;lIC>prn$!erS3~&sC zo*NBa4*=v6Y}CM5WQF%kEgCfAMw(4xEoW1wzHFY{?#DayqFfjp`|uh&kg`fQGyKcw z0Sv<0(-;>)Bmed!!)~Ob%IcYpChJZrR;Hu~BqeS2zr3?D8%v{?NCllIDg<8Gl;Eqr zUsOV8tfbJ5F*$%ai)`9sLQedC2*xY$x=!niOW3aJ-p2YvoV~=EK%_G(9cK0+Kbe`E zSmRIeqc4RoL}pN|Nrj&g!W0ASX5bARsAUjls|F+s4EYbdu$Yv3T20rqt(U_uu;AVxX&?*vV})SVIBws*YBl=A3^FJF;QS%${od7wLMNZ*!bNw}<;tVytedAd^#NdFBRvGXX_;)2x_+0o+$+?N?+!_| zq7u$D-Yo;AeUT80MAy$HW>J@*mjcYT^cPM^CEn*N8IL*@CvU0?4M$k8M7~E#bOib*EXNj|YRpqd zW7vg;B4d06TOPt1z=!uyf`F@DaYQ~~AJlZRGU=4arwNb-7VZhVP z!wb2v(Zn}XH~&icPKq$TEo$L_!-YN8{1R+gIeg+vjkBn2H~8%mM>j4HceoY4NZJ2{ z9P`B$s}N~_4!-)fhG@3pDZQaY;9 z{Ig^jBZk35R{0fMK^w5Y(ec%&i2u6z*kVU$_-#hHD|QLvu~&pJB@R%Qs905v4>}$j z_QEq@{sHyF$>RU`P+TaEjFjUB;m$Fb(N1mi*73(9lBvw0Z3#tF*aTK*du^qpri1C{ zu{Ziydmv@lbk7MO^DL&Cj@>4KxA1s%OcpP&1G7Z#ra=kvHtJ(a%&8>{EGEE;B#h** z5nYd6d8~U+`Ou3_YraGoPm?e7rKOHSk;RL>-V6C$xwjvg~w(M!_ zE3+*(`;&fln?U^*YLQ?caul5WBT@9ZM+o_GRuARb+jjV26eT_18aD>u+-z-iT6hbg z$tmcUVC{g!vF#kd)z>|!I_2o9ClUFSoLb-$3)@^L7eHtIP0S z;)>g}nG&a>4;%i;XPJFi;Eu&dB4hh zt(6AhFT-!i?To+JEAL*Y*Gdf1`3u9#fNCK?eVOhH2_)TyNm^2Z$37)9+p0Ca;Sh!J z>6Y&~1Y3ex^J4r3zAEpAsNGO{4JgItDsxx7@r|C*B8C#s5F7;h$k!4 z4G0K3)l7-uAEZ0R}7i-8`B0vjzKNKIcV-l`9jeXQnu zB(vP)(MCog1zWQp&0DUv={0sTjHMcH8nJ~Fl|QNT1-iGS==7+lY$Dhm1gPxfO^&aq zmfEd`)a(9I4w;7$=V+w~inj;kYl)r9%O-mU4#Js|;iy9(y};R*0Ib#9-Pw<^z7Ooq z+Xl}JMi*Df_=sbVk)1|oacp|(E?^1$mJB+`Gc?3#$Na3%%Y{VyAfwb-M<-5I2^@X2 zuX4JSUPWDd=%j_Hf$ZUxcuxfz$gCLfcZ;e!hnzW=d^uK8*;pS6*!jx}b!SdAW+R}K znFk3vs&&IH{OZfFq>G%Bt^HVtGB>PPe0>bVZ*4tNk zxy`k&)8YX3fzAwF*Rz`7bOmp&U*Z-aiDW?)gY&S?>!92 zQ4nk@M*pniDo_)-m;JR0M;*u4yrIMKXPH*H< z*ny2l;nw1plH`n)HbPKe zzk}ppX!SNw*{=|1Zu;z(k=FxEQ>!J7mQ;t?kd-gy0Ug6+>RvI& z+2utn$Ur!KYJ^649C-W+r5kJdBf44pDwS7T!yKYS%K`K$XKpmB)B~R82nfCnw6ka{ zdk9#iB8xyzoK0uEldZ4Mx{In+Aw)_oA2-wtQ}AVL6KlX;Ho9G`h&Qn*9njPgv>Zqs zlLk(Veg;{Z6u*5hP5)fZZ?NVL9(A{`dK9!66acDzXz@^ox#S-#f)_P#vAh_>M+;7nFloSkW^Ju?7Uh752TQ zD;yxU-R~S&Cj#|*sxQqoy5A&naYQ1t@9w|$?129uFGx+o`l$P-@5{Z;3E4v?q?uC1 zPU^~jS@dK2n)#(#3OlpQF8w)*Cd(Yl)F!AgWVO@4Yryv2)r2owz(Q$yX-q%a6G6EA zcBr0RLhpCh2jpqb&F3?> zjVCbMdgmzS9^=FiAN=6;LTRkMxE{R`%lxI89ZP$+i_5qXLQ+s>gcOG6Rzy-#C{9GX zV&OY2Wf?aKJ6fGcR(QCAA`6qOFi00Rr$vd=4>KFTN!Tld%hS;jYVB;1uQ@-VP-GYD zo+i5}*or-v&F}x@h9kH7!V$6HOG;MNz@dZ>perjTm!KyR?;vv_ZWOa@U@4biI`i_9 zK~vsMaXmv_y(ZPZ{?7OO1}pct`t2lZ@l7AK;$Q~s-bG3L0D3AXE%Zf6GGNuMiJ?d!FEbC zUX-0IntRKH_GPj-?^uMqWFNc(CIAutSpVjnGOrQIx|sDNyk&Q~eunpC%z(Ubd#hq3hC{ z-i`-tAh3|oos{2|H_5A*4AJk?^#TDZSJB(#wt3A4-}UhgO86vb%KK|WGlhMqVVPBx z^ve1d7^E;mEhp~Zo>3r$=+e@|H1$gQ7nfeS?q#G^cusU-w0b;%jh3r?eWWb`yeGN0 zG;)NCS?8SZfTLvMoIq3f+8$AZO`UoKh8rkdJ2L_<02T*(zeDcoXRq}6=L$DcUWVNe zY)7*%x++___>Wpe)}Orh{X+VZ0#_=tBZ)F|Xjx)zJSe1dZVCQHJw)E(tv}M7?s>sHgaO_Cj`VXkRhnN<9$lducp`=`6h#;S_fx75GexIDmoah+j^ zlB0yDZt(Uo@LdLYwj<$SVrIBk;FtXW$yyyjxx*suZxWr{nTB2m>M<$3^}hy>zzLX4 zPQ^6z2*Q&f6f7z0t*i*r|Cz|i1Pd^CE{(lzx8N{#p+lQjX>!06xHl`GW`J8VJ~SH^ zPSh>US4r$msIAiVa9bitdUWBQPZa@wiwkUk>_+pvO3<8t@v20qTSdR|l_Q0RK_;9#&YQCLxze( zeQ>_#UuVl(iCfjk9s-AV^hfa3cz%qEY4^;a5;B*yd(8Kjr-bV7z+QpSk8%EV+M7!o zJSN{=p2$m8O@04<;CFgTtt-8jlePFlk0P_vKSdoZ`)-&=5SR8x&*+2tD22T*c$NU4 z+W@&lf|XqFoFhsYbdEC-T+`B;fzL_kw|9R74vBA*3+HFk6*U4Fj%VAYozZ_lLnE)` zUej^t&#Rh%=zT<;Cc3*w0>&zPHgR*?maa5zjPu*_^rr53K6kgIrvn}=0vO#`vSU*u9v%466eK7pw731)?Egy@tIV|C5VCwVZ}w{%*kcr@*6mhE#V>v zV!6vc@HrUyybcaBOGFUT^w%$1N~0}|>>j*9*;HFf5ih<&$#Q1QkCos}bD0SpqjK}( z%(eF<>jIIlITs1gxSsKR-_#d=bnAiFNoAXCFStm~+AvAKS`fMz$M=))aRyve?W@+2 zSf)~ED@dq1FN+0mTl*5$%bncIp7Er1YKSwRoaCNJfDIjy3W!WGSZj|;$ayS$xz(wi zCjqwKbs%f@Cw@17oyUP#YPPFS=LWxkLVid}7-LD2bPSSS^+!ttu?cxmoQ?D|6kY&a z=mo>c3Vk&v5ZSJQWR!vNK$JnJNkZRluX_XjQF-gR7I`fRx{e#n0N4j`3~lbd*bW7Y z)?kxRI(9~#Db(cYbnum*NOXr;f^o{r{1v`J@r6$K9^f2D`OGWspX4HLlUT{ z$ds?DMx4-oW`d+{@AeHxGjWt%SlM{EAAHvam<1fc42D?= zv6#fiB?Iy&;ps5^gNv>L)dg!TkvtXKMV>0YO{sw#b?Gd@BOXw%)qPY?nP1J%QW^ZU=;tpHUK9hIAMgnH`m=Y8Gi}diSn@8mI1@Iqv*;d zN(hpQsrOzS`52x~5WnmOuif!Ctzg(a$r%>gL*u$o-KOXJz!CSsdY20T3r7 zPMhc_VzT>RD5~l1+i$*avRp^tSOzN?l994>ft>E%Ur!hfsN}%|e%PO0}@4x`UiCfcM zJ;4OCHm&g1OXjPBUY=-i9ci;PF~@uC${H=q53BipY=MlUg(1lbKaQZ4TEtaHB=%O~RgBw3xru#GA%-_ceoVD1>7f7m0K@UXXYB~4E;$+!_)ypUH3>1azdI!tvbn>sJ9r*sP zVsD%L;d`Qy7l`}}oRWIHQengHZo2~N*Wm~(2tLou312Gh@<3Z~P`YcyIicNOHuH-VB(uiStHPbO+(EZX$qK&OY=zCk3T%Ts9Imxuzozl#(De(zqqKiONP9 u{gzu<_1;wsUQ9$|1VZE?QXN*0Z#OMu+eDgkm`#Ca2-hL}FSz~R%lr@fTw_N7 From ca8cb6f2601d3e520ef9023387d442364bf21f46 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 2 Nov 2025 09:13:55 +0200 Subject: [PATCH 052/167] Add utopia-php/emails --- app/controllers/api/account.php | 6 +- composer.json | 1 + composer.lock | 162 ++++++++++++++++++++++---------- 3 files changed, 116 insertions(+), 53 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index cdd7280fb7..6c31f28754 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1675,10 +1675,12 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if (empty($user->getAttribute('email'))) { - $emailCanonical = new EmailCanonical($oauth2->getUserEmail($accessToken)); + $oauth2Email = $oauth2->getUserEmail($accessToken); + + $emailCanonical = new EmailCanonical($oauth2Email); $user - ->setAttribute('email', $oauth2->getUserEmail($accessToken)) + ->setAttribute('email', $oauth2Email) ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) diff --git a/composer.json b/composer.json index 3e00015220..f008c8e089 100644 --- a/composer.json +++ b/composer.json @@ -60,6 +60,7 @@ "utopia-php/framework": "0.33.*", "utopia-php/fetch": "0.4.*", "utopia-php/image": "0.8.*", + "utopia-php/emails": "0.6.*", "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.20.*", diff --git a/composer.lock b/composer.lock index 36c2c94265..394e2a9e3e 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": "f826d3b283b10af98dfd565c4187a83a", + "content-hash": "c53027e4009de3901769fe29b0d1a68f", "packages": [ { "name": "adhocore/jwt", @@ -3840,16 +3840,16 @@ }, { "name": "utopia-php/database", - "version": "3.0.2", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e" + "reference": "b6541a9cd9b21786a5020327f582838afdb159aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e", - "reference": "b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e", + "url": "https://api.github.com/repos/utopia-php/database/zipball/b6541a9cd9b21786a5020327f582838afdb159aa", + "reference": "b6541a9cd9b21786a5020327f582838afdb159aa", "shasum": "" }, "require": { @@ -3892,22 +3892,22 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.0.2" + "source": "https://github.com/utopia-php/database/tree/3.1.2" }, - "time": "2025-10-20T23:58:56+00:00" + "time": "2025-10-30T13:10:13+00:00" }, { "name": "utopia-php/detector", - "version": "0.2.0", + "version": "0.2.2", "source": { "type": "git", "url": "https://github.com/utopia-php/detector.git", - "reference": "795ed56169af833fd6a4ea58a6c747e05ccc7ba6" + "reference": "9a41be5f21efe2d865de79b08dff94fff85ce5e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/detector/zipball/795ed56169af833fd6a4ea58a6c747e05ccc7ba6", - "reference": "795ed56169af833fd6a4ea58a6c747e05ccc7ba6", + "url": "https://api.github.com/repos/utopia-php/detector/zipball/9a41be5f21efe2d865de79b08dff94fff85ce5e9", + "reference": "9a41be5f21efe2d865de79b08dff94fff85ce5e9", "shasum": "" }, "require": { @@ -3937,9 +3937,9 @@ ], "support": { "issues": "https://github.com/utopia-php/detector/issues", - "source": "https://github.com/utopia-php/detector/tree/0.2.0" + "source": "https://github.com/utopia-php/detector/tree/0.2.2" }, - "time": "2025-10-21T13:57:30+00:00" + "time": "2025-10-31T12:43:31+00:00" }, { "name": "utopia-php/dns", @@ -4106,6 +4106,66 @@ }, "time": "2024-05-07T02:01:25+00:00" }, + { + "name": "utopia-php/emails", + "version": "0.6.2", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/emails.git", + "reference": "9c4c40cf7c03c2e9e21364566f9b192d03ea93c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/emails/zipball/9c4c40cf7c03c2e9e21364566f9b192d03ea93c9", + "reference": "9c4c40cf7c03c2e9e21364566f9b192d03ea93c9", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "utopia-php/cli": "^0.15", + "utopia-php/domains": "^0.9", + "utopia-php/fetch": "^0.4", + "utopia-php/validators": "^0.0.2" + }, + "require-dev": { + "laravel/pint": "1.25.*", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Emails\\": "src/Emails" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eldad Fux", + "email": "eldad@appwrite.io" + } + ], + "description": "Utopia Emails library is simple and lite library for parsing and validating email addresses. This library is aiming to be as simple and easy to learn and use.", + "keywords": [ + "RFC5322", + "email", + "emails", + "framework", + "parsing", + "php", + "upf", + "utopia", + "validation" + ], + "support": { + "issues": "https://github.com/utopia-php/emails/issues", + "source": "https://github.com/utopia-php/emails/tree/0.6.2" + }, + "time": "2025-10-28T16:08:17+00:00" + }, { "name": "utopia-php/fetch", "version": "0.4.2", @@ -4395,16 +4455,16 @@ }, { "name": "utopia-php/migration", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "f5c1d2cae764290766a4c2d1546c1d51de95b67f" + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/f5c1d2cae764290766a4c2d1546c1d51de95b67f", - "reference": "f5c1d2cae764290766a4c2d1546c1d51de95b67f", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/731b3a963c58c30e0b2368695d57a7e8fcb7455c", + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c", "shasum": "" }, "require": { @@ -4444,9 +4504,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.3.2" + "source": "https://github.com/utopia-php/migration/tree/1.3.3" }, - "time": "2025-10-22T12:30:47+00:00" + "time": "2025-10-28T04:02:08+00:00" }, { "name": "utopia-php/mongo", @@ -5193,16 +5253,16 @@ }, { "name": "webmozart/assert", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "541057574806f942c94662b817a50f63f7345360" + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/541057574806f942c94662b817a50f63f7345360", - "reference": "541057574806f942c94662b817a50f63f7345360", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", "shasum": "" }, "require": { @@ -5245,9 +5305,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.1" }, - "time": "2025-10-20T12:43:39+00:00" + "time": "2025-10-29T15:56:20+00:00" }, { "name": "webonyx/graphql-php", @@ -5318,16 +5378,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.11", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "5970defc3c6e64817fe9847c0b33c87af71709c5" + "reference": "42df22195d6457e52e4c819678168470b114a816" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/5970defc3c6e64817fe9847c0b33c87af71709c5", - "reference": "5970defc3c6e64817fe9847c0b33c87af71709c5", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/42df22195d6457e52e4c819678168470b114a816", + "reference": "42df22195d6457e52e4c819678168470b114a816", "shasum": "" }, "require": { @@ -5363,9 +5423,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.4.11" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.0" }, - "time": "2025-10-24T10:03:09+00:00" + "time": "2025-10-31T10:10:25+00:00" }, { "name": "doctrine/annotations", @@ -6069,16 +6129,16 @@ }, { "name": "phpbench/phpbench", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b" + "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", - "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", + "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", "shasum": "" }, "require": { @@ -6105,7 +6165,7 @@ "ergebnis/composer-normalize": "^2.39", "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", - "phpspec/prophecy": "dev-master", + "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", @@ -6155,7 +6215,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.1" + "source": "https://github.com/phpbench/phpbench/tree/1.4.2" }, "funding": [ { @@ -6163,7 +6223,7 @@ "type": "github" } ], - "time": "2025-03-12T08:01:40+00:00" + "time": "2025-10-26T14:21:59+00:00" }, { "name": "phpstan/phpstan", @@ -7812,16 +7872,16 @@ }, { "name": "symfony/console", - "version": "v7.3.4", + "version": "v7.3.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db" + "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", + "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", "shasum": "" }, "require": { @@ -7886,7 +7946,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.4" + "source": "https://github.com/symfony/console/tree/v7.3.5" }, "funding": [ { @@ -7906,7 +7966,7 @@ "type": "tidelift" } ], - "time": "2025-09-22T15:31:00+00:00" + "time": "2025-10-14T15:46:26+00:00" }, { "name": "symfony/filesystem", @@ -7980,16 +8040,16 @@ }, { "name": "symfony/finder", - "version": "v7.3.2", + "version": "v7.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" + "reference": "9f696d2f1e340484b4683f7853b273abff94421f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", + "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f", + "reference": "9f696d2f1e340484b4683f7853b273abff94421f", "shasum": "" }, "require": { @@ -8024,7 +8084,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.2" + "source": "https://github.com/symfony/finder/tree/v7.3.5" }, "funding": [ { @@ -8044,7 +8104,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2025-10-15T18:45:57+00:00" }, { "name": "symfony/options-resolver", @@ -8856,5 +8916,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 371cab0658fd3136c21e49256402faa215090e23 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 2 Nov 2025 10:59:28 +0200 Subject: [PATCH 053/167] try catch EmailCanonical --- app/controllers/api/account.php | 48 ++++++++++++++++++++++----------- app/controllers/api/teams.php | 12 +++++++++ app/controllers/api/users.php | 12 +++++++++ 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 6c31f28754..e54dd3ef42 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -374,6 +374,13 @@ App::post('/v1/account') $passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; $password = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); + + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + try { $userId = $userId == 'unique()' ? ID::unique() : $userId; $user->setAttributes([ @@ -402,7 +409,13 @@ App::post('/v1/account') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]); + $user->removeAttribute('$sequence'); $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { @@ -1675,17 +1688,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if (empty($user->getAttribute('email'))) { - $oauth2Email = $oauth2->getUserEmail($accessToken); + $user->setAttribute('email', $oauth2->getUserEmail($accessToken)); - $emailCanonical = new EmailCanonical($oauth2Email); + try { + $emailCanonical = new EmailCanonical($user->getAttribute('email')); - $user - ->setAttribute('email', $oauth2Email) - ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) - ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) - ->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()) - ->setAttribute('emailIsFree', $emailCanonical->isFree()); + $user->setAttribute('emailCanonical', $emailCanonical->getCanonical()); + $user->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()); + $user->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()); + $user->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()); + $user->setAttribute('emailIsFree', $emailCanonical->isFree()); + } catch (Throwable) { + } } if (empty($user->getAttribute('name'))) { @@ -2230,7 +2244,11 @@ App::post('/v1/account/tokens/email') $userId = $userId === 'unique()' ? ID::unique() : $userId; - $emailCanonical = new EmailCanonical($email); + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } $user->setAttributes([ '$id' => $userId, @@ -2254,11 +2272,11 @@ App::post('/v1/account/tokens/email') 'memberships' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailCanonical->getCanonical(), - 'emailIsCanonical' => $emailCanonical->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical->isCorporate(), - 'emailIsDisposable' => $emailCanonical->isDisposable(), - 'emailIsFree' => $emailCanonical->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]); $user->removeAttribute('$sequence'); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 7398e451b5..cb956390b7 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -48,6 +48,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; +use Utopia\Emails\Email as EmailCanonical; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -564,6 +565,12 @@ App::post('/v1/teams/:teamId/memberships') throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + try { $userId = ID::unique(); $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ @@ -596,6 +603,11 @@ App::post('/v1/teams/:teamId/memberships') 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $name]), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 5498a33bf5..dccfec1101 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -49,6 +49,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; +use Utopia\Emails\Email as EmailCanonical; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -97,6 +98,12 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e } } + try { + $emailCanonical = new EmailCanonical($email ?? ''); + } catch (Throwable) { + $emailCanonical = null; + } + $password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; $user = new Document([ '$id' => $userId, @@ -124,6 +131,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $phone, $name]), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]); if ($hash === 'plaintext') { From 503145734b8ccf18f5e45b7ca1ac4e3430b8908f Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 2 Nov 2025 11:06:56 +0200 Subject: [PATCH 054/167] Move user Document out of try block --- app/controllers/api/teams.php | 77 ++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index cb956390b7..7fbf4e2d38 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -571,44 +571,47 @@ App::post('/v1/teams/:teamId/memberships') $emailCanonical = null; } + $userId = ID::unique(); + + $userDocument = new Document([ + '$id' => $userId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user($userId)), + Permission::update(Role::user($userId)), + Permission::delete(Role::user($userId)), + ], + 'email' => empty($email) ? null : $email, + 'phone' => empty($phone) ? null : $phone, + 'emailVerification' => false, + 'status' => true, + // TODO: Set password empty? + 'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS), + 'hash' => Auth::DEFAULT_ALGO, + 'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS, + /** + * Set the password update time to 0 for users created using + * team invite and OAuth to allow password updates without an + * old password + */ + 'passwordUpdate' => null, + 'registration' => DateTime::now(), + 'reset' => false, + 'name' => $name, + 'prefs' => new \stdClass(), + 'sessions' => null, + 'tokens' => null, + 'memberships' => null, + 'search' => implode(' ', [$userId, $email, $name]), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw + ]); + try { - $userId = ID::unique(); - $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ - '$id' => $userId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user($userId)), - Permission::update(Role::user($userId)), - Permission::delete(Role::user($userId)), - ], - 'email' => empty($email) ? null : $email, - 'phone' => empty($phone) ? null : $phone, - 'emailVerification' => false, - 'status' => true, - // TODO: Set password empty? - 'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS), - 'hash' => Auth::DEFAULT_ALGO, - 'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS, - /** - * Set the password update time to 0 for users created using - * team invite and OAuth to allow password updates without an - * old password - */ - 'passwordUpdate' => null, - 'registration' => DateTime::now(), - 'reset' => false, - 'name' => $name, - 'prefs' => new \stdClass(), - 'sessions' => null, - 'tokens' => null, - 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw - 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw - ]))); + $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', $userDocument)); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } From 6a41f8b2b9d587eb6ae381c88f90faed6be0d41f Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 2 Nov 2025 11:16:12 +0200 Subject: [PATCH 055/167] Remove todos --- app/controllers/api/account.php | 8 ++++---- app/controllers/api/teams.php | 4 ++-- app/controllers/api/users.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e54dd3ef42..00b4c619d7 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -412,8 +412,8 @@ App::post('/v1/account') 'emailCanonical' => $emailCanonical?->getCanonical(), 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw - 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -2275,8 +2275,8 @@ App::post('/v1/account/tokens/email') 'emailCanonical' => $emailCanonical?->getCanonical(), 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw - 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 7fbf4e2d38..3a9908ffe3 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -606,8 +606,8 @@ App::post('/v1/teams/:teamId/memberships') 'emailCanonical' => $emailCanonical?->getCanonical(), 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw - 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); try { diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index dccfec1101..d88148b5a1 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -134,8 +134,8 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'emailCanonical' => $emailCanonical?->getCanonical(), 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw - 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); if ($hash === 'plaintext') { From 0904881de851a5ef3de68b825ea862f2128ed4bf Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 2 Nov 2025 18:11:56 +0200 Subject: [PATCH 056/167] Refactor authorization handling to ensure consistent usage of the Authorization class across various modules, enhancing code maintainability and clarity. Update method signatures to include authorization as a parameter where necessary. --- app/config/storage/resource_limits.php | 4 +- app/controllers/api/messaging.php | 8 +-- app/controllers/api/storage.php | 2 +- app/controllers/api/teams.php | 2 +- app/init/resources.php | 58 +++++++++---------- app/worker.php | 4 +- composer.lock | 24 ++++---- src/Appwrite/Migration/Migration.php | 6 +- .../Platform/Modules/Compute/Base.php | 9 +-- .../Modules/Console/Http/Resources/Get.php | 2 +- .../Collections/Attributes/Action.php | 11 ++-- .../Collections/Attributes/Boolean/Create.php | 6 +- .../Attributes/Datetime/Create.php | 7 ++- .../Collections/Attributes/Email/Create.php | 4 +- .../Collections/Attributes/Enum/Create.php | 7 ++- .../Collections/Attributes/Float/Create.php | 6 +- .../Collections/Attributes/IP/Create.php | 7 ++- .../Collections/Attributes/Integer/Create.php | 6 +- .../Collections/Attributes/Line/Create.php | 6 +- .../Collections/Attributes/Point/Create.php | 6 +- .../Collections/Attributes/Polygon/Create.php | 6 +- .../Attributes/Relationship/Create.php | 4 +- .../Collections/Attributes/String/Create.php | 8 ++- .../Collections/Attributes/URL/Create.php | 7 ++- .../Collections/Attributes/XList.php | 2 +- .../Collections/Documents/Action.php | 6 +- .../Collections/Documents/Create.php | 31 +++++----- .../Collections/Documents/Delete.php | 1 + .../Databases/Collections/Documents/Get.php | 1 + .../Collections/Documents/Update.php | 3 +- .../Collections/Documents/Upsert.php | 3 +- .../Databases/Collections/Documents/XList.php | 5 +- .../Databases/Collections/Indexes/XList.php | 2 +- .../Http/Databases/Collections/Logs/XList.php | 34 +++++------ .../Http/Databases/Collections/XList.php | 2 +- .../Http/Databases/Transactions/Update.php | 2 +- .../Tables/Columns/Boolean/Create.php | 1 + .../Tables/Columns/Boolean/Update.php | 1 + .../Tables/Columns/Datetime/Create.php | 1 + .../Tables/Columns/Datetime/Update.php | 1 + .../Http/TablesDB/Tables/Columns/Delete.php | 1 + .../TablesDB/Tables/Columns/Email/Create.php | 1 + .../TablesDB/Tables/Columns/Email/Update.php | 1 + .../TablesDB/Tables/Columns/Enum/Create.php | 1 + .../TablesDB/Tables/Columns/Enum/Update.php | 1 + .../TablesDB/Tables/Columns/Float/Create.php | 1 + .../TablesDB/Tables/Columns/Float/Update.php | 1 + .../Http/TablesDB/Tables/Columns/Get.php | 1 + .../TablesDB/Tables/Columns/IP/Create.php | 1 + .../TablesDB/Tables/Columns/IP/Update.php | 1 + .../Tables/Columns/Integer/Create.php | 1 + .../Tables/Columns/Integer/Update.php | 1 + .../TablesDB/Tables/Columns/Line/Create.php | 1 + .../TablesDB/Tables/Columns/Line/Update.php | 1 + .../TablesDB/Tables/Columns/Point/Create.php | 1 + .../TablesDB/Tables/Columns/Point/Update.php | 1 + .../Tables/Columns/Polygon/Create.php | 1 + .../Tables/Columns/Polygon/Update.php | 1 + .../Tables/Columns/Relationship/Create.php | 1 + .../Tables/Columns/Relationship/Update.php | 1 + .../TablesDB/Tables/Columns/String/Create.php | 1 + .../TablesDB/Tables/Columns/String/Update.php | 1 + .../TablesDB/Tables/Columns/URL/Create.php | 1 + .../TablesDB/Tables/Columns/URL/Update.php | 1 + .../Http/TablesDB/Tables/Columns/XList.php | 1 + .../Databases/Http/TablesDB/Tables/Create.php | 1 + .../Databases/Http/TablesDB/Tables/Delete.php | 1 + .../Databases/Http/TablesDB/Tables/Get.php | 1 + .../Http/TablesDB/Tables/Indexes/Create.php | 1 + .../Http/TablesDB/Tables/Indexes/Delete.php | 1 + .../Http/TablesDB/Tables/Indexes/Get.php | 1 + .../Http/TablesDB/Tables/Indexes/XList.php | 1 + .../Http/TablesDB/Tables/Logs/XList.php | 1 + .../Http/TablesDB/Tables/Rows/Bulk/Delete.php | 1 + .../Http/TablesDB/Tables/Rows/Bulk/Update.php | 1 + .../Http/TablesDB/Tables/Rows/Bulk/Upsert.php | 1 + .../TablesDB/Tables/Rows/Column/Decrement.php | 1 + .../TablesDB/Tables/Rows/Column/Increment.php | 1 + .../Http/TablesDB/Tables/Rows/Create.php | 1 + .../Http/TablesDB/Tables/Rows/Delete.php | 1 + .../Http/TablesDB/Tables/Rows/Get.php | 1 + .../Http/TablesDB/Tables/Rows/Logs/XList.php | 1 + .../Http/TablesDB/Tables/Rows/Update.php | 1 + .../Http/TablesDB/Tables/Rows/Upsert.php | 1 + .../Http/TablesDB/Tables/Rows/XList.php | 1 + .../Databases/Http/TablesDB/Tables/Update.php | 1 + .../Http/TablesDB/Tables/Usage/Get.php | 1 + .../Databases/Http/TablesDB/Tables/XList.php | 1 + .../Http/TablesDB/Transactions/Create.php | 1 + .../Transactions/Operations/Create.php | 1 + .../Http/TablesDB/Transactions/Update.php | 1 + .../Databases/Http/TablesDB/Usage/Get.php | 1 + .../Databases/Http/TablesDB/Usage/XList.php | 1 + .../Modules/Functions/Workers/Builds.php | 16 +++-- .../Http/Deployments/Template/Create.php | 1 + .../Sites/Http/Deployments/Vcs/Create.php | 6 +- .../Sites/Http/Sites/Deployment/Update.php | 2 +- .../Http/Tokens/Buckets/Files/Action.php | 15 ++--- .../Http/Tokens/Buckets/Files/Create.php | 2 +- .../Http/Tokens/Buckets/Files/XList.php | 6 +- src/Appwrite/Platform/Tasks/Migrate.php | 9 ++- src/Appwrite/Platform/Tasks/ScheduleBase.php | 2 +- .../Platform/Tasks/StatsResources.php | 7 +-- src/Appwrite/Platform/Workers/Deletes.php | 6 +- src/Appwrite/Platform/Workers/Functions.php | 2 - src/Appwrite/Platform/Workers/Migrations.php | 4 -- src/Appwrite/Utopia/Request/Filter.php | 2 +- src/Appwrite/Utopia/Request/Filters/V20.php | 4 +- 108 files changed, 268 insertions(+), 175 deletions(-) diff --git a/app/config/storage/resource_limits.php b/app/config/storage/resource_limits.php index cfbcea5a47..43ed2b8b05 100644 --- a/app/config/storage/resource_limits.php +++ b/app/config/storage/resource_limits.php @@ -3,4 +3,6 @@ use Utopia\Image\Image; use Utopia\System\System; -Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64))); +if (\class_exists('Imagick')) { + Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64))); +} diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index ddd00a1b91..460b341f3c 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1072,7 +1072,7 @@ App::get('/v1/messaging/providers') ->inject('dbForProject') ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -2480,7 +2480,7 @@ App::get('/v1/messaging/topics') ->inject('dbForProject') ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -2882,7 +2882,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->inject('dbForProject') ->inject('authorization') ->inject('response') - ->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -3705,7 +3705,7 @@ App::get('/v1/messaging/messages') ->inject('dbForProject') ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 67c78a68d5..9a211ba290 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -790,7 +790,7 @@ App::get('/v1/storage/buckets/:bucketId/files') ->inject('dbForProject') ->inject('authorization') ->inject('mode') - ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, Authorization $authorization, string $mode) { + ->action(function (string $bucketId, array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject, Authorization $authorization, string $mode) { $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $isAPIKey = Auth::isAppUser($authorization->getRoles()); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 4fd56b3e59..563c6009aa 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -847,7 +847,7 @@ App::get('/v1/teams/:teamId/memberships') ->inject('project') ->inject('dbForProject') ->inject('authorization') - ->action(function (string $teamId, array $queries, string $search, Response $response, Document $project, Database $dbForProject, Authorization $authorization) { + ->action(function (string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject, Authorization $authorization) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { diff --git a/app/init/resources.php b/app/init/resources.php index d00cd5a6fa..7d33377f7e 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -152,7 +152,7 @@ App::setResource('queueForMigrations', function (Publisher $publisher) { App::setResource('queueForStatsResources', function (Publisher $publisher) { return new StatsResources($publisher); }, ['publisher']); -App::setResource('platforms', function (Request $request, Document $console, Document $project, Database $dbForPlatform) { +App::setResource('platforms', function (Request $request, Document $console, Document $project, Database $dbForPlatform, Authorization $authorization) { $console->setAttribute('platforms', [ // Always allow current host '$collection' => ID::custom('platforms'), 'name' => 'Current Host', @@ -200,9 +200,9 @@ App::setResource('platforms', function (Request $request, Document $console, Doc // Safe if rule with same project ID exists if (!empty($origin)) { if (System::getEnv('_APP_RULES_FORMAT') === 'md5') { - $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? ''))); + $rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? ''))); } else { - $rule = $dbForPlatform->getAuthorization()->skip( + $rule = $authorization->skip( fn () => $dbForPlatform->find('rules', [ Query::equal('domain', [$origin]), Query::limit(1) @@ -224,9 +224,9 @@ App::setResource('platforms', function (Request $request, Document $console, Doc ...$console->getAttribute('platforms', []), ...$project->getAttribute('platforms', []), ]; -}, ['request', 'console', 'project', 'dbForPlatform']); +}, ['request', 'console', 'project', 'dbForPlatform', 'authorization']); -App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForPlatform) { +App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForPlatform, $authorization) { /** @var Appwrite\Utopia\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Document $project */ @@ -235,7 +235,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons /** @var Utopia\Database\Authorization $authorization */ /** @var string $mode */ - $dbForPlatform->getAuthorization()->setDefaultStatus(true); + $authorization->setDefaultStatus(true); Auth::setCookieName('a_session_' . $project->getId()); @@ -299,7 +299,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons // if (APP_MODE_ADMIN === $mode) { // if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) { - // Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. + // $authorization->setDefaultStatus(false); // Cancel security segmentation for admin users. // } else { // $user = new Document([]); // } @@ -337,9 +337,9 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $dbForPlatform->setMetadata('user', $user->getId()); return $user; -}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform']); +}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform', 'authorization']); -App::setResource('project', function ($dbForPlatform, $request, $console) { +App::setResource('project', function ($dbForPlatform, $request, $console, $authorization) { /** @var Appwrite\Utopia\Request $request */ /** @var Utopia\Database\Database $dbForPlatform */ /** @var Utopia\Database\Document $console */ @@ -350,10 +350,10 @@ App::setResource('project', function ($dbForPlatform, $request, $console) { return $console; } - $project = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); return $project; -}, ['dbForPlatform', 'request', 'console']); +}, ['dbForPlatform', 'request', 'console', 'authorization']); App::setResource('session', function (Document $user) { if ($user->isEmpty()) { @@ -713,7 +713,7 @@ App::setResource('promiseAdapter', function ($register) { return $register->get('promiseAdapter'); }, ['register']); -App::setResource('schema', function ($utopia, $dbForProject) { +App::setResource('schema', function ($utopia, $dbForProject, $authorization) { $complexity = function (int $complexity, array $args) { $queries = Query::parseQueries($args['queries'] ?? []); @@ -723,8 +723,8 @@ App::setResource('schema', function ($utopia, $dbForProject) { return $complexity * $limit; }; - $attributes = function (int $limit, int $offset) use ($dbForProject) { - $attrs = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('attributes', [ + $attributes = function (int $limit, int $offset) use ($dbForProject, $authorization) { + $attrs = $authorization->skip(fn () => $dbForProject->find('attributes', [ Query::limit($limit), Query::offset($offset), ])); @@ -798,7 +798,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { $urls, $params, ); -}, ['utopia', 'dbForProject']); +}, ['utopia', 'dbForProject', 'authorization']); App::setResource('contributors', function () { $path = 'app/config/contributors.json'; @@ -844,7 +844,7 @@ App::setResource('smsRates', function () { return []; }); -App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform) { +App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform, Authorization $authorization) { $devKey = $request->getHeader('x-appwrite-dev-key', $request->getParam('devKey', '')); // Check if given key match project's development keys @@ -863,7 +863,7 @@ App::setResource('devKey', function (Request $request, Document $project, array $accessedAt = $key->getAttribute('accessedAt', 0); if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) { $key->setAttribute('accessedAt', DatabaseDateTime::now()); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); $dbForPlatform->purgeCachedDocument('projects', $project->getId()); } @@ -880,14 +880,14 @@ App::setResource('devKey', function (Request $request, Document $project, array /** Update access time as well */ $key->setAttribute('accessedAt', DatabaseDateTime::now()); - $key = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); + $key = $authorization->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); $dbForPlatform->purgeCachedDocument('projects', $project->getId()); } } return $key; -}, ['request', 'project', 'servers', 'dbForPlatform']); +}, ['request', 'project', 'servers', 'dbForPlatform', 'authorization']); -App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request) { +App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request, Authorization $authorization) { $teamInternalId = ''; if ($project->getId() !== 'console') { $teamInternalId = $project->getAttribute('teamInternalId', ''); @@ -897,7 +897,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A if (str_starts_with($path, '/v1/projects/:projectId')) { $uri = $request->getURI(); $pid = explode('/', $uri)[3]; - $p = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $pid)); + $p = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $pid)); $teamInternalId = $p->getAttribute('teamInternalId', ''); } elseif ($path === '/v1/projects') { $teamId = $request->getParam('teamId', ''); @@ -906,7 +906,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A return new Document([]); } - $team = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); + $team = $authorization->skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); return $team; } } @@ -915,14 +915,14 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A return new Document([]); } - $team = $dbForPlatform->getAuthorization()->skip(function () use ($dbForPlatform, $teamInternalId) { + $team = $authorization->skip(function () use ($dbForPlatform, $teamInternalId) { return $dbForPlatform->findOne('teams', [ Query::equal('$sequence', [$teamInternalId]), ]); }); return $team; -}, ['project', 'dbForPlatform', 'utopia', 'request']); +}, ['project', 'dbForPlatform', 'utopia', 'request', 'authorization']); App::setResource( 'isResourceBlocked', @@ -960,7 +960,7 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key App::setResource('executor', fn () => new Executor()); -App::setResource('resourceToken', function ($project, $dbForProject, $request) { +App::setResource('resourceToken', function ($project, $dbForProject, $request, Authorization $authorization) { $tokenJWT = $request->getParam('token'); if (!empty($tokenJWT) && !$project->isEmpty()) { // JWT authentication @@ -977,7 +977,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) { return new Document([]); } - $token = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId)); + $token = $authorization->skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId)); if ($token->isEmpty()) { return new Document([]); @@ -995,7 +995,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) { } return match ($token->getAttribute('resourceType')) { - TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject) { + TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject, $authorization) { $sequences = explode(':', $token->getAttribute('resourceInternalId')); $ids = explode(':', $token->getAttribute('resourceId')); @@ -1006,7 +1006,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) { $accessedAt = $token->getAttribute('accessedAt', 0); if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_RESOURCE_TOKEN_ACCESS)) > $accessedAt) { $token->setAttribute('accessedAt', DatabaseDateTime::now()); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token)); + $authorization->skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token)); } return new Document([ @@ -1021,7 +1021,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) { }; } return new Document([]); -}, ['project', 'dbForProject', 'request']); +}, ['project', 'dbForProject', 'request', 'authorization']); App::setResource('httpReferrer', function (Request $request): string { $referrer = $request->getReferer(); diff --git a/app/worker.php b/app/worker.php index 319be088d5..ef04ffec05 100644 --- a/app/worker.php +++ b/app/worker.php @@ -61,8 +61,8 @@ Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, $dbForPlatform = new Database($adapter, $cache); $dbForPlatform - ->setAuthorization($authorization) - ->setNamespace('_console'); + ->setAuthorization($authorization) + ->setNamespace('_console'); return $dbForPlatform; diff --git a/composer.lock b/composer.lock index 93a4d68546..b67055890f 100644 --- a/composer.lock +++ b/composer.lock @@ -5253,16 +5253,16 @@ }, { "name": "webmozart/assert", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "541057574806f942c94662b817a50f63f7345360" + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/541057574806f942c94662b817a50f63f7345360", - "reference": "541057574806f942c94662b817a50f63f7345360", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", "shasum": "" }, "require": { @@ -5305,9 +5305,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.1" }, - "time": "2025-10-20T12:43:39+00:00" + "time": "2025-10-29T15:56:20+00:00" }, { "name": "webonyx/graphql-php", @@ -5378,16 +5378,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.15", + "version": "1.4.16", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "b4a2fd9e92903c2e156f17fc5dafe102e6cfdfda" + "reference": "08f839443f678208eb56a6c5a7456dd632adfc9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b4a2fd9e92903c2e156f17fc5dafe102e6cfdfda", - "reference": "b4a2fd9e92903c2e156f17fc5dafe102e6cfdfda", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/08f839443f678208eb56a6c5a7456dd632adfc9a", + "reference": "08f839443f678208eb56a6c5a7456dd632adfc9a", "shasum": "" }, "require": { @@ -5423,9 +5423,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.4.15" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.16" }, - "time": "2025-10-28T04:52:59+00:00" + "time": "2025-10-29T08:39:55+00:00" }, { "name": "doctrine/annotations", diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 27387b8867..4d2db6a3dc 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -13,6 +13,7 @@ use Utopia\Database\Exception\Limit; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; use Utopia\Database\PDO; +use Utopia\Database\Validator\Authorization; abstract class Migration { @@ -125,6 +126,7 @@ abstract class Migration Document $project, Database $dbForProject, Database $dbForPlatform, + Authorization $authorization, ?callable $getProjectDB = null ): self { $this->project = $project; @@ -132,8 +134,8 @@ abstract class Migration $this->dbForPlatform = $dbForPlatform; $this->getProjectDB = $getProjectDB; - $this->dbForPlatform->getAuthorization()->disable(); - $this->dbForPlatform->getAuthorization()->setDefaultStatus(false); + $authorization->disable(); + $authorization->setDefaultStatus(false); return $this; } diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index eb6dd6d75d..70014b2728 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -13,6 +13,7 @@ use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\VCS\Adapter\Git\GitHub; @@ -141,7 +142,7 @@ class Base extends Action return $deployment; } - public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document + public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, Authorization $authorization, string $referenceType = 'branch', string $reference = ''): Document { $deploymentId = ID::unique(); $providerInstallationId = $installation->getAttribute('providerInstallationId', ''); @@ -237,7 +238,7 @@ class Base extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $dbForProject->getAuthorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -263,7 +264,7 @@ class Base extends Action $domain = "commit-" . substr($commitDetails['commitHash'], 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - $dbForProject->getAuthorization()->skip( + $authorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -300,7 +301,7 @@ class Base extends Action $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - $dbForProject->getAuthorization()->skip( + $authorization()->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php index 55a60a5cbf..a0f8e9421e 100644 --- a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php +++ b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php @@ -126,7 +126,7 @@ class Get extends Action throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.'); } - $document = $authorization()->skip(fn () => $dbForPlatform->findOne('rules', [ + $document = $authorization->skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal('domain', [$value]), ])); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php index 5b41c42200..6c5305f299 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php @@ -17,6 +17,7 @@ use Utopia\Database\Exception\Relationship as RelationshipException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Exception\Truncate as TruncateException; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Structure; use Utopia\Platform\Action as UtopiaAction; use Utopia\Swoole\Response as SwooleResponse; @@ -291,7 +292,7 @@ abstract class Action extends UtopiaAction }; } - protected function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): Document + protected function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): Document { $key = $attribute->getAttribute('key'); $type = $attribute->getAttribute('type', ''); @@ -309,7 +310,7 @@ abstract class Action extends UtopiaAction throw new Exception($this->getSpatialTypeNotSupportedException()); } - $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -370,7 +371,7 @@ abstract class Action extends UtopiaAction \in_array($attribute->getAttribute('type'), Database::SPATIAL_TYPES) && $attribute->getAttribute('required') ) { - $hasData = !$dbForProject->getAuthorization()->skip(fn () => $dbForProject + $hasData = !$authorization->skip(fn () => $dbForProject ->findOne('database_' . $db->getSequence() . '_collection_' . $collection->getSequence())) ->isEmpty(); @@ -471,9 +472,9 @@ abstract class Action extends UtopiaAction return $attribute; } - protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, string $type, int $size = null, string $filter = null, string|bool|int|float|array $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document + protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, Authorization $authorization, string $type, int $size = null, string $filter = null, string|bool|int|float|array $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document { - $db = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php index 6c8e5dcf3d..b22b6318c1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -68,10 +69,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -80,7 +82,7 @@ class Create extends Action 'required' => $required, 'default' => $default, 'array' => $array, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php index 1f2098e7af..5e5dc25c57 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; @@ -69,10 +70,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute( $databaseId, @@ -89,7 +91,8 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents + $queueForEvents, + $authorization ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php index cbfd66e4d9..e848dec37c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php @@ -13,6 +13,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,10 +70,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute( $databaseId, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php index 98ed83861d..fb7216b241 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php @@ -13,6 +13,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -72,10 +73,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { if (!is_null($default) && !\in_array($default, $elements, true)) { throw new Exception($this->getInvalidValueException(), 'Default value not found in elements'); @@ -97,7 +99,8 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents + $queueForEvents, + $authorization ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php index 83deb92edc..b5085b804e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php @@ -13,6 +13,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -73,10 +74,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $min ??= -PHP_FLOAT_MAX; $max ??= PHP_FLOAT_MAX; @@ -99,7 +101,7 @@ class Create extends Action 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, 'formatOptions' => ['min' => $min, 'max' => $max], - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $formatOptions = $attribute->getAttribute('formatOptions', []); if (!empty($formatOptions)) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php index 6e6264466c..99f683521c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,10 +70,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute( $databaseId, @@ -89,7 +91,8 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents + $queueForEvents, + $authorization ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php index 090d63c403..8fe7ccfde7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php @@ -13,6 +13,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -73,10 +74,11 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $min ??= \PHP_INT_MIN; $max ??= \PHP_INT_MAX; @@ -101,7 +103,7 @@ class Create extends Action 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_INT_RANGE, 'formatOptions' => ['min' => $min, 'max' => $max], - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $formatOptions = $attribute->getAttribute('formatOptions', []); if (!empty($formatOptions)) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php index f691fc29cf..7a92b3e13d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -69,17 +70,18 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_LINESTRING, 'required' => $required, 'default' => $default - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php index aae715ba1e..9aff7cba34 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -69,17 +70,18 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_POINT, 'required' => $required, 'default' => $default, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php index 6fbbd46d2c..bc3dd75ace 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -69,17 +70,18 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_POLYGON, 'required' => $required, 'default' => $default, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php index 411fd3bf5b..8a11019168 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php @@ -91,7 +91,7 @@ class Create extends Action $key ??= $relatedCollectionId; $twoWayKey ??= $collectionId; - $database = $authorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -150,7 +150,7 @@ class Create extends Action 'twoWayKey' => $twoWayKey, 'onDelete' => $onDelete, ] - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); foreach ($attribute->getAttribute('options', []) as $k => $option) { $attribute->setAttribute($k, $option); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php index 1527c4d1d9..564a72269a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php @@ -14,6 +14,7 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -76,6 +77,7 @@ class Create extends Action ->inject('queueForDatabase') ->inject('queueForEvents') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } @@ -92,7 +94,8 @@ class Create extends Action Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, - array $plan + array $plan, + Authorization $authorization ): void { if (!App::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() . '.'); @@ -131,7 +134,8 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents + $queueForEvents, + $authorization ); $attribute->setAttribute('encrypt', $encrypt); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php index ce0175966b..15295a0850 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,6 +70,7 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } @@ -82,7 +84,8 @@ class Create extends Action UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, - Event $queueForEvents + Event $queueForEvents, + Authorization $authorization ): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -92,7 +95,7 @@ class Create extends Action 'default' => $default, 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_URL, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php index 798e6a3771..be61b260b3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php @@ -68,7 +68,7 @@ class XList extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index d42dca57fa..7c5428931d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -258,10 +258,9 @@ abstract class Action extends AppwriteAction Document $collection, Document $document, Database $dbForProject, - Authorization $authorization, - /* options */ array &$collectionsCache, + Authorization $authorization, ?int &$operations = null, ): bool { @@ -324,7 +323,8 @@ abstract class Action extends AppwriteAction document: $relation, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - operations: $operations + operations: $operations, + authorization: $authorization ); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index d7ec69777d..d6d56b66fc 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -179,19 +179,19 @@ class Create extends Action $documents = [$data]; } - $isAPIKey = Auth::isAppUser($authorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($isBulk && !$isAPIKey && !$isPrivilegedUser) { throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE); } - $database = $authorization()->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization()->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -205,7 +205,7 @@ class Create extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Bulk create is not supported for ' . $this->getSDKNamespace() .' with relationship ' . $this->getStructureContext()); } - $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $dbForProject) { + $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $dbForProject, $authorization) { $allowedPermissions = [ Database::PERMISSION_READ, Database::PERMISSION_UPDATE, @@ -248,8 +248,8 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization()->hasRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $authorization()->getRoles()) . ')'); + if (!$authorization->hasRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $authorization->getRoles()) . ')'); } } } @@ -260,25 +260,25 @@ class Create extends Action $operations = 0; - $checkPermissions = function (Document $collection, Document $document, string $permission) use ($isAPIKey, $isPrivilegedUser, &$checkPermissions, $dbForProject, $database, &$operations) { + $checkPermissions = function (Document $collection, Document $document, string $permission) use ($isAPIKey, $isPrivilegedUser, &$checkPermissions, $dbForProject, $database, &$operations, $authorization) { $operations++; $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validCollection = $authorization()->isValid( + $validCollection = $authorization->isValid( new Input($permission, $collection->getPermissionsByType($permission)) ); if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$validCollection) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } if ($permission === Database::PERMISSION_UPDATE) { - $validDocument = $authorization()->isValid( + $validDocument = $authorization->isValid( new Input($permission, $document->getUpdate()) ); $valid = $validCollection || $validDocument; if ($documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization()->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } } @@ -303,7 +303,7 @@ class Create extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $authorization()->skip( + $relatedCollection = $authorization->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -319,7 +319,7 @@ class Create extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $current = $authorization()->skip( + $current = $authorization->skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId()) ); @@ -374,7 +374,7 @@ class Create extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization()->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -471,6 +471,7 @@ class Create extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, + authorization: $authorization ); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index fe754b6a68..cc98255dff 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -204,6 +204,7 @@ class Delete extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, + authorization: $authorization ); $queueForStatsUsage diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php index 5dcef98b90..7fd00b4ad1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php @@ -125,6 +125,7 @@ class Get extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, + authorization: $authorization, operations: $operations ); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index 128f57708f..3dbc86682e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -167,7 +167,7 @@ class Update extends Action $operations = 0; - $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations) { + $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations, $authorization) { $operations++; $relationships = \array_filter( @@ -334,6 +334,7 @@ class Update extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, + authorization: $authorization, ); $response->dynamic($document, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 139ff7c466..9fac2af060 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -177,7 +177,7 @@ class Upsert extends Action $newDocument = new Document($data); $operations = 0; - $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations) { + $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations, $authorization) { $operations++; $relationships = \array_filter( @@ -355,6 +355,7 @@ class Upsert extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, + authorization: $authorization ); $relationships = \array_map( diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index e10e6abfd9..5c01b1e215 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -77,7 +77,7 @@ class XList extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState, Authorization $authorization): void { $isAPIKey = Auth::isAppUser($authorization->getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); @@ -161,7 +161,8 @@ class XList extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - operations: $operations, + authorization: $authorization, + operations: $operations ); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php index 268ae4fc09..d6e59dc4fa 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php @@ -70,7 +70,7 @@ class XList extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { /** @var Document $database */ $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php index 928ba55ee0..f193c15299 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php @@ -116,9 +116,9 @@ class XList extends Action $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) - $os = $detector->getOS(); - $client = $detector->getClient(); - $device = $detector->getDevice(); + $os = $detector->getOS() ?: []; + $client = $detector->getClient() ?: []; + $device = $detector->getDevice() ?: []; $output[$i] = new Document([ 'event' => $log['event'], @@ -126,20 +126,20 @@ class XList extends Action 'userEmail' => $log['data']['userEmail'] ?? null, 'userName' => $log['data']['userName'] ?? null, 'mode' => $log['data']['mode'] ?? null, - 'ip' => $log['ip'], - 'time' => $log['time'], - 'osCode' => $os['osCode'], - 'osName' => $os['osName'], - 'osVersion' => $os['osVersion'], - 'clientType' => $client['clientType'], - 'clientCode' => $client['clientCode'], - 'clientName' => $client['clientName'], - 'clientVersion' => $client['clientVersion'], - 'clientEngine' => $client['clientEngine'], - 'clientEngineVersion' => $client['clientEngineVersion'], - 'deviceName' => $device['deviceName'], - 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'ip' => $log['ip'] ?? null, + 'time' => $log['time'] ?? null, + 'osCode' => $os['osCode'] ?? null, + 'osName' => $os['osName'] ?? null, + 'osVersion' => $os['osVersion'] ?? null, + 'clientType' => $client['clientType'] ?? null, + 'clientCode' => $client['clientCode'] ?? null, + 'clientName' => $client['clientName'] ?? null, + 'clientVersion' => $client['clientVersion'] ?? null, + 'clientEngine' => $client['clientEngine'] ?? null, + 'clientEngineVersion' => $client['clientEngineVersion'] ?? null, + 'deviceName' => $device['deviceName'] ?? null, + 'deviceBrand' => $device['deviceBrand'] ?? null, + 'deviceModel' => $device['deviceModel'] ?? null ]); $record = $geodb->get($log['ip']); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php index a45c4c539a..11b60e35a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php @@ -71,7 +71,7 @@ class XList extends Action ->callback($this->action(...)); } - public function action(string $databaseId, array $queries, string $search, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, array $queries, string $search, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index 24e149800d..4f488445f0 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -138,7 +138,7 @@ class Update extends Action $databaseOperations = []; try { - $dbForProject->withTransaction(function () use ($dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, $queueForEvents, $queueForStatsUsage, $queueForRealtime, $queueForFunctions, $queueForWebhooks) { + $dbForProject->withTransaction(function () use ($dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, $queueForEvents, $queueForStatsUsage, $queueForRealtime, $queueForFunctions, $queueForWebhooks, $authorization) { $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'committing', ]))); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php index 039964b2c6..687898b83a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php @@ -59,6 +59,7 @@ class Create extends BooleanCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php index 7df901a1cc..bc6ceabb72 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php @@ -61,6 +61,7 @@ class Update extends BooleanUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php index db5a3059f1..7f5a5ae4f5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php @@ -61,6 +61,7 @@ class Create extends DatetimeCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php index 151422af75..fbcec4cd0b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php @@ -63,6 +63,7 @@ class Update extends DatetimeUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php index 26f4ffa898..62152453fe 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php @@ -58,6 +58,7 @@ class Delete extends AttributesDelete ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php index 3a8d492e4e..65ab2cb573 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php @@ -60,6 +60,7 @@ class Create extends EmailCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php index 4d32489357..2a6d0f56b8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php @@ -62,6 +62,7 @@ class Update extends EmailUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php index 68dc2f8e08..a66834b438 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php @@ -63,6 +63,7 @@ class Create extends EnumCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php index 3b611a5fde..07c78070f6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php @@ -65,6 +65,7 @@ class Update extends EnumUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php index 9fe6987cab..e62dec9477 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php @@ -62,6 +62,7 @@ class Create extends FloatCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php index 023e2e834e..360b680f0f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php @@ -64,6 +64,7 @@ class Update extends FloatUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php index c20ef58a39..0e7e079a02 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php @@ -61,6 +61,7 @@ class Get extends AttributesGet ->param('key', '', new Key(), 'Column Key.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php index 81ca8da81f..180777c550 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php @@ -60,6 +60,7 @@ class Create extends IPCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php index 0db95b0206..645b54bdd9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php @@ -62,6 +62,7 @@ class Update extends IPUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php index dfca51a6c5..a5fd5b0b06 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php @@ -62,6 +62,7 @@ class Create extends IntegerCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php index a1568d069b..24192b3efb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php @@ -64,6 +64,7 @@ class Update extends IntegerUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php index 4aa173707b..469fb6851f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php @@ -61,6 +61,7 @@ class Create extends LineCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php index d3823445a2..a485453ba5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php @@ -63,6 +63,7 @@ class Update extends LineUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php index b8ae563def..715348e1f4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php @@ -61,6 +61,7 @@ class Create extends PointCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php index 3c855e137c..3df8e0aee7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php @@ -63,6 +63,7 @@ class Update extends PointUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php index e0a2cf32cd..38c9eaf284 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php @@ -61,6 +61,7 @@ class Create extends PolygonCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php index 866bbaf8b0..905f165de6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php @@ -63,6 +63,7 @@ class Update extends PolygonUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php index 0a6c76d8c5..b76b03d86b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php @@ -72,6 +72,7 @@ class Create extends RelationshipCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php index b645454be1..8eea93d286 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php @@ -64,6 +64,7 @@ class Update extends RelationshipUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php index 6fe9fd679c..5ecb781f83 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php @@ -65,6 +65,7 @@ class Create extends StringCreate ->inject('queueForDatabase') ->inject('queueForEvents') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php index 5ec9b78dda..60b9ba85ce 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php @@ -65,6 +65,7 @@ class Update extends StringUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php index 99ec36b721..1b0f30418e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php @@ -60,6 +60,7 @@ class Create extends URLCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php index 51168b0383..8528e8fb05 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php @@ -62,6 +62,7 @@ class Update extends URLUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php index 1e0b641b32..950d38f8a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php @@ -52,6 +52,7 @@ class XList extends AttributesXList ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php index 4f62200d7c..d71295170f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php @@ -62,6 +62,7 @@ class Create extends CollectionCreate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php index de068d5b29..79b9e7beef 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php @@ -55,6 +55,7 @@ class Delete extends CollectionDelete ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php index be6ec5d9e7..e264ec0411 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php @@ -50,6 +50,7 @@ class Get extends CollectionGet ->param('tableId', '', new UID(), 'Table ID.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php index 3802ee32b8..2d14785bb8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php @@ -66,6 +66,7 @@ class Create extends IndexCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php index 57ab466ee8..cb552a086c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php @@ -61,6 +61,7 @@ class Delete extends IndexDelete ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php index 271d842631..3c01f1b64d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php @@ -52,6 +52,7 @@ class Get extends IndexGet ->param('key', null, new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php index 0ea52eaf1b..a6206f06dd 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php @@ -54,6 +54,7 @@ class XList extends IndexXList ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php index 0680649544..f9111287c3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php @@ -50,6 +50,7 @@ class XList extends CollectionLogXList ->inject('dbForProject') ->inject('locale') ->inject('geodb') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php index 86e9a48f63..902034441e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php @@ -65,6 +65,7 @@ class Delete extends DocumentsDelete ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php index 5005ab4f41..3ab636139e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php @@ -67,6 +67,7 @@ class Update extends DocumentsUpdate ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php index d0a1f08003..6dc575fe04 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php @@ -67,6 +67,7 @@ class Upsert extends DocumentsUpsert ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php index d42cf5e9eb..605db6d024 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php @@ -66,6 +66,7 @@ class Decrement extends DecrementDocumentAttribute ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php index c58e16c8e3..d86cb373a6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php @@ -66,6 +66,7 @@ class Increment extends IncrementDocumentAttribute ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php index bfc832f2b5..927ea517cf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php @@ -110,6 +110,7 @@ class Create extends DocumentCreate ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php index 687b1c8c11..ef5303776d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php @@ -69,6 +69,7 @@ class Delete extends DocumentDelete ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php index f8b70516b6..16cb5c5557 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php @@ -57,6 +57,7 @@ class Get extends DocumentGet ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php index 5f1efa2953..5117e77ea9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php @@ -51,6 +51,7 @@ class XList extends DocumentLogXList ->inject('dbForProject') ->inject('locale') ->inject('geodb') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php index cb1d5888cf..87c0831356 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php @@ -68,6 +68,7 @@ class Update extends DocumentUpdate ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php index 0bc373cc93..bf8403d930 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php @@ -71,6 +71,7 @@ class Upsert extends DocumentUpsert ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php index b96e84b722..d8eb08ae17 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php @@ -58,6 +58,7 @@ class XList extends DocumentXList ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php index 8424b37a6d..c80bf914f3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php @@ -61,6 +61,7 @@ class Update extends CollectionUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php index 0fb44ee94a..b8be7edd56 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php @@ -52,6 +52,7 @@ class Get extends CollectionUsageGet ->param('tableId', '', new UID(), 'Table ID.') ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php index 5e8fcfc3c8..eafb291037 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php @@ -55,6 +55,7 @@ class XList extends CollectionXList ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php index bc79b86ca3..1c6f0f95ca 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php @@ -50,6 +50,7 @@ class Create extends TransactionsCreate ->inject('response') ->inject('dbForProject') ->inject('user') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php index 5a98f22f37..2e3b73e395 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php @@ -54,6 +54,7 @@ class Create extends OperationsCreate ->inject('dbForProject') ->inject('transactionState') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php index 4d55af93a4..250c9e0bc4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php @@ -60,6 +60,7 @@ class Update extends TransactionsUpdate ->inject('queueForRealtime') ->inject('queueForFunctions') ->inject('queueForWebhooks') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php index 89b9fbd8c2..87be8a9eab 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php @@ -48,6 +48,7 @@ class Get extends DatabaseUsageGet ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php index 0bd96fc40a..2cde337f5f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php @@ -46,6 +46,7 @@ class XList extends DatabaseUsageXList ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index c2b5f0262f..93bac56fa4 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -27,7 +27,6 @@ use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Detector\Detection\Rendering\SSR; use Utopia\Detector\Detection\Rendering\XStatic; use Utopia\Detector\Detector\Rendering; @@ -919,11 +918,11 @@ class Builds extends Action ->trigger(); try { - $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('rules', [ + $rule = $dbForPlatform->findOne('rules', [ Query::equal("projectInternalId", [$project->getSequence()]), Query::equal("type", ["deployment"]), Query::equal('deploymentInternalId', [$deployment->getSequence()]), - ])); + ]); if ($rule->isEmpty()) { throw new \Exception("Rule for build not found"); @@ -933,7 +932,7 @@ class Builds extends Action $client->setTimeout(\intval($resource->getAttribute('timeout', '15'))); $client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON); - $bucket = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = $dbForPlatform->getDocument('buckets', 'screenshots'); $configs = [ 'screenshotLight' => [ @@ -1055,7 +1054,7 @@ class Builds extends Action 'metadata' => ['content_type' => $mimeType], ]); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file)); + $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file); $deployment->setAttribute($key, $fileId); } @@ -1278,7 +1277,7 @@ class Builds extends Action ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $resource->getAttribute('schedule')) ->setAttribute('active', !empty($resource->getAttribute('schedule')) && !empty($resource->getAttribute('deploymentId'))); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule); } Console::info('Deployment action finished'); @@ -1485,7 +1484,6 @@ class Builds extends Action * @return void * @throws Structure * @throws \Utopia\Database\Exception - * @throws Authorization * @throws Conflict * @throws Restricted */ @@ -1573,11 +1571,11 @@ class Builds extends Action default => throw new \Exception('Invalid resource type') }; - $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->findOne('rules', [ + $rule = $dbForPlatform->findOne('rules', [ Query::equal("projectInternalId", [$project->getSequence()]), Query::equal("type", ["deployment"]), Query::equal("deploymentInternalId", [$deployment->getSequence()]), - ])); + ]); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; $previewUrl = match($resource->getCollection()) { diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index 377b3321ae..e849ee92aa 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -125,6 +125,7 @@ class Create extends Base template: $template, github: $github, activate: $activate, + authorization: $authorization, ); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php index ddad5d793a..09dc4a1618 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -72,6 +73,7 @@ class Create extends Base ->inject('queueForEvents') ->inject('queueForBuilds') ->inject('gitHub') + ->inject('authorization') ->callback($this->action(...)); } @@ -87,7 +89,8 @@ class Create extends Base Document $project, Event $queueForEvents, Build $queueForBuilds, - GitHub $github + GitHub $github, + Authorization $authorization ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -110,6 +113,7 @@ class Create extends Base template: $template, github: $github, activate: $activate, + authorization: $authorization, reference: $reference, referenceType: $type ); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index 382039f85d..e3cab865a9 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -106,7 +106,7 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - $authorization->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { + $authorization->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment, $authorization) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php index 709a12a957..2c57c57611 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php @@ -7,29 +7,30 @@ use Appwrite\Extend\Exception; use Utopia\Database\Database; use Utopia\Database\Validator\Authorization\Input; use Utopia\Platform\Action as UtopiaAction; +use Utopia\Database\Validator\Authorization; class Action extends UtopiaAction { - protected function getFileAndBucket(Database $dbForProject, string $bucketId, string $fileId): array + protected function getFileAndBucket(Database $dbForProject, Authorization $authorization, string $bucketId, string $fileId): array { - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($dbForProject->getAuthorization()->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $dbForProject->getAuthorization()->getDescription()); + if (!$authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); if ($fileSecurity) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($file->isEmpty()) { diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index 0a5a3da15b..b632bbad77 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -77,7 +77,7 @@ class Create extends Action * @var Document $bucket * @var Document $file */ - ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId); + ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $bucketId, $fileId); $fileSecurity = $bucket->getAttribute('fileSecurity', false); $bucketPermission = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php index 8a9301713b..78cef8251f 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php @@ -16,6 +16,7 @@ use Utopia\Database\Query; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; +use Utopia\Database\Validator\Authorization; class XList extends Action { @@ -57,12 +58,13 @@ class XList extends Action ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $bucketId, string $fileId, array $queries, bool $includeTotal, Response $response, Database $dbForProject) + public function action(string $bucketId, string $fileId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Authorization $authorization) { - ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId); + ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $bucketId, $fileId); $queries = Query::parseQueries($queries); $queries[] = Query::equal('resourceType', [TOKENS_RESOURCE_TYPE_FILES]); diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 1fd7525937..cc6981fa1b 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -31,7 +31,7 @@ class Migrate extends Action ->inject('dbForPlatform') ->inject('getProjectDB') ->inject('register') - ->inject('authorization') + ->inject('authorisation') ->callback($this->action(...)); } @@ -50,7 +50,6 @@ class Migrate extends Action Registry $register, Authorization $authorization ): void { - $authorization->disable(); if (!\array_key_exists($version, Migration::$versions)) { Console::error("No migration found for version $version."); @@ -68,14 +67,14 @@ class Migrate extends Action $count = 0; $total = $dbForPlatform->count('projects') + 1; - $dbForPlatform->foreach('projects', function (Document $project) use ($dbForPlatform, $getProjectDB, $register, $migration, &$count, $total) { + $dbForPlatform->foreach('projects', function (Document $project) use ($dbForPlatform, $getProjectDB, $register, $migration, &$count, $total, $authorization) { /** @var Database $dbForProject */ $dbForProject = $getProjectDB($project); $dbForProject->disableValidation(); try { $migration - ->setProject($project, $dbForProject, $dbForPlatform, $getProjectDB) + ->setProject($project, $dbForProject, $dbForPlatform, $authorization, $getProjectDB) ->setPDO($register->get('db', true)) ->execute(); } catch (\Throwable $th) { @@ -90,7 +89,7 @@ class Migrate extends Action try { $migration - ->setProject($console, $getProjectDB($console), $dbForPlatform, $getProjectDB) + ->setProject($console, $getProjectDB($console), $dbForPlatform, $authorization, $getProjectDB) ->setPDO($register->get('db', true)) ->execute(); } catch (\Throwable $th) { diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 4e8a5beb76..33a01346a8 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -61,7 +61,7 @@ abstract class ScheduleBase extends Action $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + $dbForPlatform->updateDocument('projects', $project->getId(), $project); } } } diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index b7da5d227d..87d4858351 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -8,7 +8,6 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\System\System; /** @@ -49,7 +48,7 @@ class StatsResources extends Action ->callback($this->action(...)); } - public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue, Authorization $authorization): void + public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue): void { $this->logError = $logError; $this->dbForPlatform = $dbForPlatform; @@ -62,9 +61,7 @@ class StatsResources extends Action $interval = (int) System::getEnv('_APP_STATS_RESOURCES_INTERVAL', '3600'); - Console::loop(function () use ($queue, $dbForPlatform, $authorization) { - $authorization->disable(); - $authorization->setDefaultStatus(false); + Console::loop(function () use ($queue, $dbForPlatform) { $last24Hours = (new \DateTime())->sub(\DateInterval::createFromDateString('24 hours')); /** diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index ee0587fad4..60e615efc1 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -19,7 +19,6 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception as DatabaseException; -use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; @@ -197,7 +196,6 @@ class Deletes extends Action * @param string $datetime * @param Document|null $document * @return void - * @throws Authorization * @throws Conflict * @throws Restricted * @throws Structure @@ -953,14 +951,14 @@ class Deletes extends Action } Console::info("Deleting screenshots for deployment " . $deployment->getId()); - $bucket = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = $dbForPlatform->getDocument('buckets', 'screenshots'); if ($bucket->isEmpty()) { Console::error('Failed to get bucket for deployment screenshots'); return; } foreach ($screenshotIds as $id) { - $file = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $id)); + $file = $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $id); if ($file->isEmpty()) { Console::error('Failed to get deployment screenshot: ' . $id); diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index df1833ad33..8ed95ac2fc 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -15,7 +15,6 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; @@ -326,7 +325,6 @@ class Functions extends Action * @param string|null $eventData * @param string|null $executionId * @return void - * @throws Authorization * @throws Structure * @throws \Utopia\Database\Exception * @throws Conflict diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index fe06f9c366..1d6e57fe94 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -11,7 +11,6 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; @@ -223,7 +222,6 @@ class Migrations extends Action } /** - * @throws Authorization * @throws Structure * @throws Conflict * @throws \Utopia\Database\Exception @@ -282,7 +280,6 @@ class Migrations extends Action } /** - * @throws Authorization * @throws Conflict * @throws Restricted * @throws Structure @@ -421,7 +418,6 @@ class Migrations extends Action * @param Document $migration * @param Mail $queueForMails * @return void - * @throws Authorization * @throws Structure * @throws \Utopia\Database\Exception * @throws Exception diff --git a/src/Appwrite/Utopia/Request/Filter.php b/src/Appwrite/Utopia/Request/Filter.php index 56fed746d9..6d47d4d150 100644 --- a/src/Appwrite/Utopia/Request/Filter.php +++ b/src/Appwrite/Utopia/Request/Filter.php @@ -10,7 +10,7 @@ abstract class Filter private array $params; private ?Database $dbForProject; - public function __construct(Database $dbForProject = null, array $params = []) + public function __construct(?Database $dbForProject = null, array $params = []) { $this->params = $params; $this->dbForProject = $dbForProject; diff --git a/src/Appwrite/Utopia/Request/Filters/V20.php b/src/Appwrite/Utopia/Request/Filters/V20.php index df369a0b9a..e130178083 100644 --- a/src/Appwrite/Utopia/Request/Filters/V20.php +++ b/src/Appwrite/Utopia/Request/Filters/V20.php @@ -149,10 +149,10 @@ class V20 extends Filter } try { - $collection = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( + $collection = $dbForProject->getDocument( 'database_' . $database->getSequence(), $collectionId - )); + ); if ($collection->isEmpty()) { return []; } From 9b82dd04117963311fff5393cf72b32427c074c1 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 2 Nov 2025 18:14:31 +0200 Subject: [PATCH 057/167] Update composer.lock to reflect version upgrades for utopia-php/detector (0.2.1 to 0.2.2) and appwrite/sdk-generator (1.4.16 to 1.5.0), including updated references and source URLs. --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index b67055890f..8e139e31b2 100644 --- a/composer.lock +++ b/composer.lock @@ -3898,16 +3898,16 @@ }, { "name": "utopia-php/detector", - "version": "0.2.1", + "version": "0.2.2", "source": { "type": "git", "url": "https://github.com/utopia-php/detector.git", - "reference": "89f96e864220de13800cf398a1f1686a85401eaa" + "reference": "9a41be5f21efe2d865de79b08dff94fff85ce5e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/detector/zipball/89f96e864220de13800cf398a1f1686a85401eaa", - "reference": "89f96e864220de13800cf398a1f1686a85401eaa", + "url": "https://api.github.com/repos/utopia-php/detector/zipball/9a41be5f21efe2d865de79b08dff94fff85ce5e9", + "reference": "9a41be5f21efe2d865de79b08dff94fff85ce5e9", "shasum": "" }, "require": { @@ -3937,9 +3937,9 @@ ], "support": { "issues": "https://github.com/utopia-php/detector/issues", - "source": "https://github.com/utopia-php/detector/tree/0.2.1" + "source": "https://github.com/utopia-php/detector/tree/0.2.2" }, - "time": "2025-10-27T13:38:33+00:00" + "time": "2025-10-31T12:43:31+00:00" }, { "name": "utopia-php/dns", @@ -5378,16 +5378,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.4.16", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "08f839443f678208eb56a6c5a7456dd632adfc9a" + "reference": "42df22195d6457e52e4c819678168470b114a816" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/08f839443f678208eb56a6c5a7456dd632adfc9a", - "reference": "08f839443f678208eb56a6c5a7456dd632adfc9a", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/42df22195d6457e52e4c819678168470b114a816", + "reference": "42df22195d6457e52e4c819678168470b114a816", "shasum": "" }, "require": { @@ -5423,9 +5423,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.4.16" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.0" }, - "time": "2025-10-29T08:39:55+00:00" + "time": "2025-10-31T10:10:25+00:00" }, { "name": "doctrine/annotations", From d96c7eb3e9f61fcbf4041d1ea5076d29f0168eaf Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 2 Nov 2025 18:58:41 +0200 Subject: [PATCH 058/167] Enhance TransactionState to utilize Authorization class for improved transaction management. Updated method signatures and resource initialization to include authorization, ensuring consistent handling across the application. --- app/init/resources.php | 6 +++--- src/Appwrite/Databases/TransactionState.php | 11 +++++++---- .../Http/Databases/Collections/Attributes/Action.php | 4 ++-- .../Collections/Attributes/Boolean/Update.php | 5 ++++- .../Collections/Attributes/Datetime/Update.php | 5 ++++- .../Databases/Collections/Attributes/Email/Update.php | 5 ++++- .../Databases/Collections/Attributes/Enum/Update.php | 5 ++++- .../Databases/Collections/Attributes/Float/Update.php | 5 ++++- .../Databases/Collections/Attributes/IP/Update.php | 5 ++++- .../Collections/Attributes/Integer/Update.php | 5 ++++- .../Databases/Collections/Attributes/Line/Update.php | 5 ++++- .../Databases/Collections/Attributes/Point/Update.php | 5 ++++- .../Collections/Attributes/Polygon/Update.php | 5 ++++- .../Collections/Attributes/Relationship/Update.php | 6 +++++- .../Collections/Attributes/String/Update.php | 6 +++++- .../Databases/Collections/Attributes/URL/Update.php | 6 +++++- 16 files changed, 67 insertions(+), 22 deletions(-) diff --git a/app/init/resources.php b/app/init/resources.php index 7d33377f7e..db2cc093f0 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -1054,6 +1054,6 @@ App::setResource('httpReferrerSafe', function (Request $request, string $httpRef return $referrer; }, ['request', 'httpReferrer', 'platforms', 'dbForPlatform', 'project', 'utopia']); -App::setResource('transactionState', function (Database $dbForProject) { - return new TransactionState($dbForProject); -}, ['dbForProject']); +App::setResource('transactionState', function (Database $dbForProject, Authorization $authorization) { + return new TransactionState($dbForProject, $authorization); +}, ['dbForProject', 'authorization']); diff --git a/src/Appwrite/Databases/TransactionState.php b/src/Appwrite/Databases/TransactionState.php index 44ba62c4a4..8e098774e6 100644 --- a/src/Appwrite/Databases/TransactionState.php +++ b/src/Appwrite/Databases/TransactionState.php @@ -7,6 +7,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception; use Utopia\Database\Exception\Timeout; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; /** * Service for managing transaction state and providing transaction-aware document operations @@ -19,10 +20,12 @@ use Utopia\Database\Query; class TransactionState { private Database $dbForProject; - - public function __construct(Database $dbForProject) + private Authorization $authorization; + /** @var Authorization $authorization */ + public function __construct(Database $dbForProject, Authorization $authorization) { $this->dbForProject = $dbForProject; + $this->authorization = $authorization; } @@ -341,12 +344,12 @@ class TransactionState */ private function getTransactionState(string $transactionId): array { - $transaction = $this->dbForProject->getAuthorization()->skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId)); + $transaction = $this->authorization->skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId)); if ($transaction->isEmpty() || $transaction->getAttribute('status') !== 'pending') { return []; } - $operations = $this->dbForProject->getAuthorization()->skip(fn () => $this->dbForProject->find('transactionLogs', [ + $operations = $this->authorization->skip(fn () => $this->dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php index 6c5305f299..9bf487bca2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php @@ -614,7 +614,7 @@ abstract class Action extends UtopiaAction } } else { try { - $dbForProject->updateAttribute( + $authorization->skip(fn () => $dbForProject->updateAttribute( collection: $collectionId, id: $key, size: $size, @@ -622,7 +622,7 @@ abstract class Action extends UtopiaAction default: $default, formatOptions: $options, newKey: $newKey ?? null - ); + )); } catch (DuplicateException) { throw new Exception($this->getDuplicateException()); } catch (IndexException $e) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php index d4724ea551..97d7010a03 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -68,10 +69,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -79,6 +81,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_BOOLEAN, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php index cb4d0d924b..7760bf009c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; @@ -69,10 +70,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -80,6 +82,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_DATETIME, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php index 2446722f7a..108d3b4fce 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,10 +70,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -80,6 +82,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_EMAIL, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php index 23dc807360..72037db0db 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -71,10 +72,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,6 +84,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_ENUM, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php index 7f295a1a94..96970e7708 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -71,10 +72,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,6 +84,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_FLOAT, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php index 6cedf10760..077a20754d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,10 +70,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -80,6 +82,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_IP, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php index b6ae79bd8a..8afb055686 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -71,10 +72,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,6 +84,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_INTEGER, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php index 52f04ba5bc..cecf59ff7d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Validator\Key; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,10 +70,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -80,6 +82,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_LINESTRING, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php index 73964ab461..6490b778e1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -69,10 +70,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -80,6 +82,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_POINT, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php index 23eb06f45d..a4d05c15bf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php @@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attribu use Appwrite\Event\Event; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attributes\Action; use Appwrite\SDK\AuthType; +use Utopia\Database\Validator\Authorization; use Appwrite\SDK\ContentType; use Appwrite\SDK\Deprecated; use Appwrite\SDK\Method; @@ -69,10 +70,11 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -80,6 +82,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_POLYGON, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php index 897cbd434f..cc7d1f83eb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -70,6 +71,7 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } @@ -81,7 +83,8 @@ class Update extends Action ?string $newKey, UtopiaResponse $response, Database $dbForProject, - Event $queueForEvents + Event $queueForEvents, + Authorization $authorization ): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -89,6 +92,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_RELATIONSHIP, required: false, options: [ diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php index 8614dfb202..6a71b7e6e5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -72,6 +73,7 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } @@ -85,7 +87,8 @@ class Update extends Action ?string $newKey, UtopiaResponse $response, Database $dbForProject, - Event $queueForEvents + Event $queueForEvents, + Authorization $authorization ): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -93,6 +96,7 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, + authorization: $authorization, type: Database::VAR_STRING, size: $size, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php index 7ba12ad98a..e33f2a6509 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php @@ -11,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,6 +70,7 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } @@ -81,7 +83,8 @@ class Update extends Action ?string $newKey, UtopiaResponse $response, Database $dbForProject, - Event $queueForEvents + Event $queueForEvents, + Authorization $authorization ): void { $attribute = $this->updateAttribute( $databaseId, @@ -89,6 +92,7 @@ class Update extends Action $key, $dbForProject, $queueForEvents, + $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_URL, default: $default, From dbccb16784bb79fcb19f27b87d811bc9afd6caee Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 2 Nov 2025 19:01:59 +0200 Subject: [PATCH 059/167] linter --- .../Http/Databases/Collections/Attributes/Line/Update.php | 2 +- .../Http/Databases/Collections/Attributes/Polygon/Update.php | 2 +- .../Modules/Tokens/Http/Tokens/Buckets/Files/Action.php | 2 +- .../Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php index cecf59ff7d..1c2845c795 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php @@ -11,8 +11,8 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php index a4d05c15bf..ed4ab4ac48 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php @@ -5,13 +5,13 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attribu use Appwrite\Event\Event; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attributes\Action; use Appwrite\SDK\AuthType; -use Utopia\Database\Validator\Authorization; use Appwrite\SDK\ContentType; use Appwrite\SDK\Deprecated; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php index 2c57c57611..e05418b90d 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php @@ -5,9 +5,9 @@ namespace Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files; use Appwrite\Auth\Auth; use Appwrite\Extend\Exception; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Platform\Action as UtopiaAction; -use Utopia\Database\Validator\Authorization; class Action extends UtopiaAction { diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php index 78cef8251f..13da92cbc6 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php @@ -13,10 +13,10 @@ use Exception; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; -use Utopia\Database\Validator\Authorization; class XList extends Action { From c13aed651ae811b71ff265032176e2df005d1050 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 2 Nov 2025 21:24:11 +0200 Subject: [PATCH 060/167] Refactor storage file retrieval to use queries directly for counting, improving consistency in authorization handling. Update Action class to remove unnecessary authorization skip, and include authorization in Email/Create class constructor for better dependency management. --- app/controllers/api/storage.php | 6 ++---- .../Http/Databases/Collections/Attributes/Action.php | 4 ++-- .../Http/Databases/Collections/Attributes/Email/Create.php | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 9a211ba290..beb212b0ef 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -842,15 +842,13 @@ App::get('/v1/storage/buckets/:bucketId/files') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; - try { if ($fileSecurity && !$valid) { $files = $dbForProject->find('bucket_' . $bucket->getSequence(), $queries); - $total = $includeTotal ? $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT) : 0; + $total = $includeTotal ? $dbForProject->count('bucket_' . $bucket->getSequence(), $queries, APP_LIMIT_COUNT) : 0; } else { $files = $authorization->skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); - $total = $authorization->skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)); + $total = $includeTotal ? $authorization->skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $queries, APP_LIMIT_COUNT)) : 0; } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php index 9bf487bca2..6c5305f299 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php @@ -614,7 +614,7 @@ abstract class Action extends UtopiaAction } } else { try { - $authorization->skip(fn () => $dbForProject->updateAttribute( + $dbForProject->updateAttribute( collection: $collectionId, id: $key, size: $size, @@ -622,7 +622,7 @@ abstract class Action extends UtopiaAction default: $default, formatOptions: $options, newKey: $newKey ?? null - )); + ); } catch (DuplicateException) { throw new Exception($this->getDuplicateException()); } catch (IndexException $e) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php index e848dec37c..c6dd85be75 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php @@ -91,7 +91,8 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents + $queueForEvents, + $authorization ); $response From cd1b2b6c053510cfd04395b4bfc2449827ae62b1 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 09:07:44 +0200 Subject: [PATCH 061/167] Refactor authorization handling by replacing method calls with direct class references, ensuring consistent usage of the Authorization class across various modules. Update method signatures to include Authorization as a parameter where necessary, and remove unnecessary injections. Additionally, correct the documentation in CHANGES.md for clarity. --- .github/workflows/auto-label-issue.yml | 22 ------------------- CHANGES.md | 2 +- app/controllers/api/users.php | 1 - .../Platform/Modules/Compute/Base.php | 4 ++-- .../Collections/Documents/Bulk/Delete.php | 3 ++- .../Collections/Documents/Bulk/Upsert.php | 3 ++- .../TablesDB/Tables/Columns/IP/Update.php | 1 - .../Tables/Columns/Integer/Update.php | 1 - .../TablesDB/Tables/Columns/Point/Update.php | 1 - .../Tables/Columns/Polygon/Update.php | 1 - .../Tables/Columns/Relationship/Update.php | 1 - .../TablesDB/Tables/Columns/String/Update.php | 1 - .../TablesDB/Tables/Columns/URL/Update.php | 1 - .../Http/TablesDB/Tables/Indexes/Create.php | 11 ++++++++++ src/Appwrite/Utopia/Response.php | 2 +- 15 files changed, 19 insertions(+), 36 deletions(-) delete mode 100644 .github/workflows/auto-label-issue.yml diff --git a/.github/workflows/auto-label-issue.yml b/.github/workflows/auto-label-issue.yml deleted file mode 100644 index e0eb0de98d..0000000000 --- a/.github/workflows/auto-label-issue.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Auto Label Issue - -on: - issues: - types: [opened] - -permissions: - issues: write - contents: read - -jobs: - labeler: - runs-on: ubuntu-latest - steps: - - name: Issue Labeler - uses: github/issue-labeler@v3.4 - with: - configuration-path: .github/labeler.yml - enable-versioned-regex: false - include-title: 1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGES.md b/CHANGES.md index 7460fc64b5..74b46b7edc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1543,7 +1543,7 @@ * Bump console to version 3.2.7 [#7148](https://github.com/appwrite/appwrite/pull/7148) * Chore update database to 0.45.2 [#7138](https://github.com/appwrite/appwrite/pull/7138) * Implement queue thresholds for the health API [#7123](https://github.com/appwrite/appwrite/pull/7123) -* Add Authorization->skip to the usage worker [#7124](https://github.com/appwrite/appwrite/pull/7124) +* Add Authorization::skip to the usage worker [#7124](https://github.com/appwrite/appwrite/pull/7124) ## Bug fixes * fix: use queueForDeletes in git installation delete endpoint [#7140](https://github.com/appwrite/appwrite/pull/7140) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 5534a70acc..08591794dd 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2624,7 +2624,6 @@ App::get('/v1/users/usage') ->inject('response') ->inject('dbForProject') ->inject('authorization') - ->inject('register') ->action(function (string $range, Response $response, Database $dbForProject, Authorization $authorization) { $periods = Config::getParam('usage', []); diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 70014b2728..8ff5d88dd4 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -264,7 +264,7 @@ class Base extends Action $domain = "commit-" . substr($commitDetails['commitHash'], 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - $authorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -301,7 +301,7 @@ class Base extends Action $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - $authorization()->skip( + $authorization->skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php index 4b1251e016..afca273830 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php @@ -19,6 +19,7 @@ use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; @@ -83,7 +84,7 @@ class Delete extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void + public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, Authorization $authorization, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void { $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php index a2156484a8..63bd3d1205 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php @@ -19,6 +19,7 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Relationship as RelationshipException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; @@ -85,7 +86,7 @@ class Upsert extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void + public function action(string $databaseId, string $collectionId, array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, Authorization $authorization): void { $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php index 645b54bdd9..0db95b0206 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php @@ -62,7 +62,6 @@ class Update extends IPUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php index 24192b3efb..a1568d069b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php @@ -64,7 +64,6 @@ class Update extends IntegerUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php index 3df8e0aee7..3c855e137c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php @@ -63,7 +63,6 @@ class Update extends PointUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php index 905f165de6..866bbaf8b0 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php @@ -63,7 +63,6 @@ class Update extends PolygonUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php index 8eea93d286..b645454be1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php @@ -64,7 +64,6 @@ class Update extends RelationshipUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php index 60b9ba85ce..5ec9b78dda 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php @@ -65,7 +65,6 @@ class Update extends StringUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php index 8528e8fb05..51168b0383 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php @@ -62,7 +62,6 @@ class Update extends URLUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php index 2d14785bb8..165f014320 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php @@ -2,6 +2,8 @@ namespace Appwrite\Platform\Modules\Databases\Http\TablesDB\Tables\Indexes; +use Appwrite\Event\Database as EventDatabase; +use Appwrite\Event\Event; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Indexes\Create as IndexCreate; use Appwrite\SDK\AuthType; use Appwrite\SDK\ContentType; @@ -9,6 +11,7 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,4 +72,12 @@ class Create extends IndexCreate ->inject('authorization') ->callback($this->action(...)); } + + public function action(string $databaseId, string $tableId, string $key, string $type, array $columns, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + { + // Map TablesDB parameters to Collections API parameters + // tableId -> collectionId + // columns -> attributes + parent::action($databaseId, $tableId, $key, $type, $columns, $orders, $lengths, $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + } } diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index da614a5a6a..c92d49ade8 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -809,7 +809,7 @@ class Response extends SwooleResponse } if ($rule['sensitive']) { - $roles = $this->authorization?->getRoles() ?? []; + $roles = $this->authorization->getRoles() ?? []; $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); From a3742bc65e8492e828048c088c9bf35dff4c15d6 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 09:13:04 +0200 Subject: [PATCH 062/167] compose.lock --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index be5e4b2fa3..8e139e31b2 100644 --- a/composer.lock +++ b/composer.lock @@ -8932,5 +8932,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } From f613a06d19963044e71d0f7750d7fac79c8cb662 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 10:04:01 +0200 Subject: [PATCH 063/167] composer.lock --- composer.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.lock b/composer.lock index 5b70c4a229..8b06671dc1 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": "6a0ff41b0f382016b899d52307df5983", + "content-hash": "881b001010468bad06d1eef0693e8ed0", "packages": [ { "name": "adhocore/jwt", @@ -3922,8 +3922,8 @@ "utopia" ], "support": { - "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance" + "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance", + "issues": "https://github.com/utopia-php/database/issues" }, "time": "2025-10-27T08:34:29+00:00" }, From 89d5a28c28fecad389c52075e22b9b8e73f2554d Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 10:37:05 +0200 Subject: [PATCH 064/167] Refactor authorization handling to consistently utilize the Authorization class across multiple controllers and functions. Update method signatures to include Authorization as a parameter, ensuring cleaner and more maintainable code. This change enhances the overall structure and readability of the authorization logic. --- app/controllers/general.php | 55 ++++++++++++++++++---------------- app/controllers/shared/api.php | 52 +++++++++++++++++--------------- app/http.php | 18 ++++++----- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index 332f0c1d15..4da331fcc4 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -56,7 +56,7 @@ Config::setParam('domainVerification', false); Config::setParam('cookieDomain', 'localhost'); Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE); -function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) +function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Authorization $authorization, ?Key $apiKey) { $host = $request->getHostname() ?? ''; if (!empty($previewHostname)) { @@ -65,9 +65,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw // TODO: @christyjacob remove once we migrate the rules in 1.7.x if (System::getEnv('_APP_RULES_FORMAT') === 'md5') { - $rule = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('rules', md5($host))); + $rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', md5($host))); } else { - $rule = $dbForPlatform->getAuthorization()->skip( + $rule = $authorization->skip( fn () => $dbForPlatform->find('rules', [ Query::equal('domain', [$host]), Query::limit(1) @@ -108,7 +108,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $projectId = $rule->getAttribute('projectId'); - $project = $dbForPlatform->getAuthorization()->skip( + $project = $authorization->skip( fn () => $dbForPlatform->getDocument('projects', $projectId) ); @@ -116,7 +116,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } /** @@ -155,7 +155,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw /** @var Document $deployment */ if (!empty($rule->getAttribute('deploymentId', ''))) { - $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); + $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); } else { // 1.6.x DB schema compatibility // TODO: Make sure deploymentId is never empty, and remove this code @@ -169,15 +169,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw // Document of site or function $resource = $resourceType === 'function' ? - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $resourceId)) : - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('sites', $resourceId)); + $authorization->skip(fn () => $dbForProject->getDocument('functions', $resourceId)) : + $authorization->skip(fn () => $dbForProject->getDocument('sites', $resourceId)); // ID of active deployments // Attempts to use attribute from both schemas (1.6 and 1.7) $activeDeploymentId = $resource->getAttribute('deploymentId', $resource->getAttribute('deployment', '')); // Get deployment document, as intended originally - $deployment = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId)); + $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId)); } if ($deployment->getAttribute('resourceType', '') === 'functions') { @@ -196,8 +196,8 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $resource = $type === 'function' ? - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) : - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', ''))); + $authorization->skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) : + $authorization->skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', ''))); $isPreview = $type === 'function' ? false : ($rule->getAttribute('trigger', '') !== 'manual'); @@ -239,7 +239,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw $userExists = false; $userId = $payload['userId'] ?? ''; if (!empty($userId)) { - $user = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); if (!$user->isEmpty() && $user->getAttribute('status', false)) { $userExists = true; } @@ -252,7 +252,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $membershipExists = false; - $project = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); if (!$project->isEmpty() && isset($user)) { $teamId = $project->getAttribute('teamId', ''); $membership = $user->find('teamId', $teamId, 'memberships'); @@ -863,7 +863,8 @@ App::init() ->inject('apiKey') ->inject('httpReferrer') ->inject('httpReferrerSafe') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $platforms, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe) { + ->inject('authorization') + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $platforms, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe, Authorization $authorization) { /* * Appwrite Router */ @@ -871,7 +872,7 @@ App::init() $mainDomain = System::getEnv('_APP_DOMAIN', ''); // Only run Router when external domain if ($host !== $mainDomain || !empty($previewHostname)) { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -919,7 +920,7 @@ App::init() } elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) { Console::warning('Skipping SSL certificates generation on ACME challenge.'); } else { - $dbForPlatform->getAuthorization()->disable(); + $authorization->disable(); $envDomain = System::getEnv('_APP_DOMAIN', ''); $mainDomain = null; @@ -989,7 +990,7 @@ App::init() } $domains[$domain->get()] = true; - $dbForPlatform->getAuthorization()->reset(); // ensure authorization is re-enabled + $authorization->reset(); // ensure authorization is re-enabled } Config::setParam('domains', $domains); } @@ -1125,7 +1126,8 @@ App::options() ->inject('project') ->inject('devKey') ->inject('apiKey') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey) { + ->inject('authorization') + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey, Authorization $authorization) { /* * Appwrite Router */ @@ -1133,7 +1135,7 @@ App::options() $mainDomain = System::getEnv('_APP_DOMAIN', ''); // Only run Router when external domain if ($host !== $mainDomain || !empty($previewHostname)) { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -1442,7 +1444,8 @@ App::get('/robots.txt') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('apiKey') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { + ->inject('authorization') + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey, Authorization $authorization) { $host = $request->getHostname() ?? ''; $consoleDomain = System::getEnv('_APP_CONSOLE_DOMAIN', ''); $mainDomain = System::getEnv('_APP_DOMAIN', ''); @@ -1451,7 +1454,7 @@ App::get('/robots.txt') $template = new View(__DIR__ . '/../views/general/robots.phtml'); $response->text($template->render(false)); } else { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -1476,7 +1479,8 @@ App::get('/humans.txt') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('apiKey') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { + ->inject('authorization') + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey, Authorization $authorization) { $host = $request->getHostname() ?? ''; $consoleDomain = System::getEnv('_APP_CONSOLE_DOMAIN', ''); $mainDomain = System::getEnv('_APP_DOMAIN', ''); @@ -1485,7 +1489,7 @@ App::get('/humans.txt') $template = new View(__DIR__ . '/../views/general/humans.phtml'); $response->text($template->render(false)); } else { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -1569,7 +1573,8 @@ App::get('/v1/ping') ->inject('project') ->inject('dbForPlatform') ->inject('queueForEvents') - ->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents) { + ->inject('authorization') + ->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents, Authorization $authorization) { if ($project->isEmpty() || $project->getId() === 'console') { throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND); } @@ -1581,7 +1586,7 @@ App::get('/v1/ping') ->setAttribute('pingCount', $pingCount) ->setAttribute('pingedAt', $pingedAt); - $dbForPlatform->getAuthorization()->skip(function () use ($dbForPlatform, $project) { + $authorization->skip(function () use ($dbForPlatform, $project) { $dbForPlatform->updateDocument('projects', $project->getId(), $project); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 8ea1198c27..a1b9e7fef4 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -28,6 +28,7 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; use Utopia\Queue\Publisher; use Utopia\System\System; @@ -232,7 +233,8 @@ App::init() ->inject('mode') ->inject('team') ->inject('apiKey') - ->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey) { + ->inject('authorization') + ->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) { $route = $utopia->getRoute(); if ($project->isEmpty()) { @@ -262,7 +264,7 @@ App::init() if ($apiKey->getRole() === Auth::USER_ROLE_APPS) { // Disable authorization checks for API keys - $dbForPlatform->getAuthorization()->setDefaultStatus(false); + $authorization->setDefaultStatus(false); $user = new Document([ '$id' => '', @@ -335,14 +337,14 @@ App::init() $scopes = \array_merge($scopes, $roles[$role]['scopes']); } - $dbForPlatform->getAuthorization()->setDefaultStatus(false); // Cancel security segmentation for admin users. + $authorization->setDefaultStatus(false); // Cancel security segmentation for admin users. } $scopes = \array_unique($scopes); - $dbForPlatform->getAuthorization()->addRole($role); - foreach (Auth::getRoles($user, $dbForPlatform->getAuthorization()) as $authRole) { - $dbForPlatform->getAuthorization()->addRole($authRole); + $authorization->addRole($role); + foreach (Auth::getRoles($user, $authorization) as $authRole) { + $authorization->addRole($authRole); } // Update project last activity @@ -350,7 +352,7 @@ App::init() $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } } @@ -385,7 +387,7 @@ App::init() if ( array_key_exists($namespace, $project->getAttribute('services', [])) && !$project->getAttribute('services', [])[$namespace] - && !(Auth::isPrivilegedUser($dbForPlatform->getAuthorization()->getRoles()) || Auth::isAppUser($dbForPlatform->getAuthorization()->getRoles())) + && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) ) { throw new Exception(Exception::GENERAL_SERVICE_DISABLED); } @@ -445,14 +447,15 @@ App::init() ->inject('plan') ->inject('devKey') ->inject('telemetry') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry) use ($usageDatabaseListener, $eventDatabaseListener) { + ->inject('authorization') + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, Authorization $authorization) use ($usageDatabaseListener, $eventDatabaseListener) { $route = $utopia->getRoute(); if ( array_key_exists('rest', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['rest'] - && !(Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()) || Auth::isAppUser($dbForProject->getAuthorization() ->getRoles())) + && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } @@ -482,7 +485,7 @@ App::init() $closestLimit = null; - $roles = $dbForProject->getAuthorization()->getRoles(); + $roles = $authorization->getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -582,10 +585,10 @@ App::init() if ($useCache) { $route = $utopia->match($request); $isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview'; - $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser($authorization->getRoles()); $key = $request->cacheIdentifier(); - $cacheLog = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key)); $cache = new Cache( new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); @@ -602,17 +605,17 @@ App::init() if ($type === 'bucket' && (!$isImageTransformation || !$isDisabled)) { $bucketId = $parts[1] ?? null; - $bucket = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); - $isPrivilegedUser = Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $dbForProject->getAuthorization()->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); if (!$fileSecurity && !$valid && !$isToken) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -623,7 +626,7 @@ App::init() if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { @@ -634,11 +637,11 @@ App::init() throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } //Do not update transformedAt if it's a console user - if (!Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles())) { + if (!Auth::isPrivilegedUser($authorization->getRoles())) { $transformedAt = $file->getAttribute('transformedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) { $file->setAttribute('transformedAt', DateTime::now()); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); + $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); } } } @@ -734,7 +737,8 @@ App::shutdown() ->inject('queueForWebhooks') ->inject('queueForRealtime') ->inject('dbForProject') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject) use ($parseLabel) { + ->inject('authorization') + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization) use ($parseLabel) { $responsePayload = $response->getPayload(); @@ -860,11 +864,11 @@ App::shutdown() $key = $request->cacheIdentifier(); $signature = md5($data['payload']); - $cacheLog = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key)); $accessedAt = $cacheLog->getAttribute('accessedAt', 0); $now = DateTime::now(); if ($cacheLog->isEmpty()) { - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('cache', new Document([ + $authorization->skip(fn () => $dbForProject->createDocument('cache', new Document([ '$id' => $key, 'resource' => $resource, 'resourceType' => $resourceType, @@ -874,7 +878,7 @@ App::shutdown() ]))); } elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) { $cacheLog->setAttribute('accessedAt', $now); - $dbForProject->getAuthorization()->skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog)); + $authorization->skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog)); // Overwrite the file every APP_CACHE_UPDATE seconds to update the file modified time that is used in the TTL checks in cache->load() $cache->save($key, $data['payload']); } @@ -886,7 +890,7 @@ App::shutdown() } if ($project->getId() !== 'console') { - if (!Auth::isPrivilegedUser($dbForProject->getAuthorization()->getRoles())) { + if (!Auth::isPrivilegedUser($authorization->getRoles())) { $fileSize = 0; $file = $request->getFiles('file'); if (!empty($file)) { diff --git a/app/http.php b/app/http.php index 5ca72c45ed..b1e757012f 100644 --- a/app/http.php +++ b/app/http.php @@ -25,6 +25,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Logger\Log; use Utopia\Logger\Log\User; use Utopia\Pools\Group; @@ -258,7 +259,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg createDatabase($app, 'getLogsDB', 'logs', $collections['logs'], $pools); // create appwrite database, `dbForPlatform` is a direct access call. - createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections) { + createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections, $app) { + $authorization = $app->getResource('authorization'); + if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) { $audit = new Audit($dbForPlatform); $audit->setup(); @@ -317,9 +320,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes); } - if ($dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { + if ($authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { Console::info(" └── Creating screenshots bucket..."); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ + $authorization->skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ '$id' => ID::custom('screenshots'), '$collection' => ID::custom('buckets'), 'name' => 'Screenshots', @@ -334,7 +337,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg 'search' => 'buckets Screenshots', ]))); - $bucket = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = $authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); Console::info(" └── Creating files collection for screenshots bucket..."); $files = $collections['buckets']['files'] ?? []; @@ -362,7 +365,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg 'orders' => $index['orders'], ]), $files['indexes']); - $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes)); + $authorization->skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes)); } }); @@ -559,7 +562,7 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) { /** @var Utopia\Database\Database $dbForPlatform */ $dbForPlatform = $app->getResource('dbForPlatform'); - Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $domains, &$lastSyncUpdate) { + Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $domains, &$lastSyncUpdate, $app) { try { $time = DateTime::now(); $limit = 1000; @@ -576,7 +579,8 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) { } $results = []; try { - $results = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->find('rules', $queries)); + $authorization = $app->getResource('authorization'); + $results = $authorization->skip(fn () => $dbForPlatform->find('rules', $queries)); } catch (Throwable $th) { Console::error($th->getMessage()); } From 5709265f6c79eedd2c5593af03314f12e6d8cad2 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 11:02:30 +0200 Subject: [PATCH 065/167] linter --- app/http.php | 3 +-- .../Http/Databases/Collections/Documents/Bulk/Delete.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/http.php b/app/http.php index b1e757012f..568571fad2 100644 --- a/app/http.php +++ b/app/http.php @@ -25,7 +25,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Logger\Log; use Utopia\Logger\Log\User; use Utopia\Pools\Group; @@ -261,7 +260,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg // create appwrite database, `dbForPlatform` is a direct access call. createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections, $app) { $authorization = $app->getResource('authorization'); - + if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) { $audit = new Audit($dbForPlatform); $audit->setup(); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php index afca273830..d3e18420a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php @@ -84,7 +84,7 @@ class Delete extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, Authorization $authorization, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void + public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void { $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { From 3391563829846184d4e5e418b5c493044ca5cc61 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 11:07:17 +0200 Subject: [PATCH 066/167] Remove unused Authorization import from Bulk Delete.php to clean up code and improve maintainability. --- .../Http/Databases/Collections/Documents/Bulk/Delete.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php index d3e18420a7..4b1251e016 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php @@ -19,7 +19,6 @@ use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; From 02dd275be4fc08623fce930bc598d874d4eee588 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 11:54:50 +0200 Subject: [PATCH 067/167] Update composer.lock with new reference for utopia-php/database and modify Upsert action method to remove unused Authorization parameter and enhance document validation. This improves code clarity and maintainability. --- composer.lock | 8 ++++---- .../Http/Databases/Collections/Documents/Bulk/Upsert.php | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 8b06671dc1..6d7f1c307a 100644 --- a/composer.lock +++ b/composer.lock @@ -3844,12 +3844,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "22123ad30782be131ecad4e9298b843d8daf387b" + "reference": "61d06624a5b96b6e4665ef1de740e31428b868ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/22123ad30782be131ecad4e9298b843d8daf387b", - "reference": "22123ad30782be131ecad4e9298b843d8daf387b", + "url": "https://api.github.com/repos/utopia-php/database/zipball/61d06624a5b96b6e4665ef1de740e31428b868ec", + "reference": "61d06624a5b96b6e4665ef1de740e31428b868ec", "shasum": "" }, "require": { @@ -3925,7 +3925,7 @@ "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance", "issues": "https://github.com/utopia-php/database/issues" }, - "time": "2025-10-27T08:34:29+00:00" + "time": "2025-11-03T09:42:43+00:00" }, { "name": "utopia-php/detector", diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php index 80e53170da..6c869723a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php @@ -19,7 +19,6 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Relationship as RelationshipException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; @@ -86,7 +85,7 @@ class Upsert extends Action ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void { $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { From d721425cfecbdaebdf063feb6afac9bb8abfc098 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 12:33:07 +0200 Subject: [PATCH 068/167] composer.lock --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 6d7f1c307a..1f10c437cf 100644 --- a/composer.lock +++ b/composer.lock @@ -3844,12 +3844,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "61d06624a5b96b6e4665ef1de740e31428b868ec" + "reference": "5464da0f13d159096b1ee62acfddf0440be36596" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/61d06624a5b96b6e4665ef1de740e31428b868ec", - "reference": "61d06624a5b96b6e4665ef1de740e31428b868ec", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5464da0f13d159096b1ee62acfddf0440be36596", + "reference": "5464da0f13d159096b1ee62acfddf0440be36596", "shasum": "" }, "require": { @@ -3925,7 +3925,7 @@ "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance", "issues": "https://github.com/utopia-php/database/issues" }, - "time": "2025-11-03T09:42:43+00:00" + "time": "2025-11-03T10:08:55+00:00" }, { "name": "utopia-php/detector", From e1fbaf14eb6cfb1fb7850cef992a0c8767f9adde Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 12:51:21 +0200 Subject: [PATCH 069/167] Inject authorization dependency into the Update class for improved authorization handling in relationship updates. --- .../Http/TablesDB/Tables/Columns/Relationship/Update.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php index b645454be1..8eea93d286 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php @@ -64,6 +64,7 @@ class Update extends RelationshipUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } From dc43b5977ffad4310564e0f2297c54a9b6bf9aac Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 3 Nov 2025 12:58:22 +0200 Subject: [PATCH 070/167] Inject authorization dependency into the Update class to enhance authorization handling for string column updates. --- .../Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php | 1 + .../Databases/Http/TablesDB/Tables/Columns/Integer/Update.php | 1 + .../Databases/Http/TablesDB/Tables/Columns/Point/Update.php | 1 + .../Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php | 1 + .../Databases/Http/TablesDB/Tables/Columns/String/Update.php | 1 + .../Databases/Http/TablesDB/Tables/Columns/URL/Update.php | 1 + 6 files changed, 6 insertions(+) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php index 0db95b0206..645b54bdd9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php @@ -62,6 +62,7 @@ class Update extends IPUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php index a1568d069b..24192b3efb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php @@ -64,6 +64,7 @@ class Update extends IntegerUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php index 3c855e137c..3df8e0aee7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php @@ -63,6 +63,7 @@ class Update extends PointUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php index 866bbaf8b0..905f165de6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php @@ -63,6 +63,7 @@ class Update extends PolygonUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php index 5ec9b78dda..60b9ba85ce 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php @@ -65,6 +65,7 @@ class Update extends StringUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php index 51168b0383..8528e8fb05 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php @@ -62,6 +62,7 @@ class Update extends URLUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') + ->inject('authorization') ->callback($this->action(...)); } } From 10a9845898b57a7e2e8b9f1ab30b9d91b1e79005 Mon Sep 17 00:00:00 2001 From: Hemachandar Date: Mon, 3 Nov 2025 16:53:44 +0530 Subject: [PATCH 071/167] fix: Throw error when file token expiry is in the past --- phpunit.xml | 1 + .../Http/Tokens/Buckets/Files/Create.php | 11 +++++-- .../Modules/Tokens/Http/Tokens/Update.php | 11 +++++-- .../Tokens/TokensConsoleClientTest.php | 29 ++++++++++++++++-- .../Tokens/TokensCustomServerTest.php | 30 ++++++++++++++++--- 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 4c4e55ea4e..a8578995c1 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -31,6 +31,7 @@ ./tests/e2e/Services/Locale ./tests/e2e/Services/Projects ./tests/e2e/Services/Storage + ./tests/e2e/Services/Tokens ./tests/e2e/Services/Webhooks ./tests/e2e/Services/Messaging ./tests/e2e/Services/Migrations diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index fe7a0187e9..0d905838a7 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -17,7 +17,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; -use Utopia\Validator\Nullable; +use Utopia\Validator\Text; class Create extends Action { @@ -61,7 +61,7 @@ class Create extends Action )) ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File unique ID.') - ->param('expire', null, new Nullable(new DatetimeValidator()), 'Token expiry date', true) + ->param('expire', null, new Text(100), 'Token expiry date', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') @@ -70,6 +70,13 @@ class Create extends Action public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents): void { + if (!is_null($expire)) { + $validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_DAYS, offset: 0); + if (!$validator->isValid($expire)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now'); + } + } + /** * @var Document $bucket diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php index 7a15708011..b1b670532d 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php @@ -14,7 +14,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; -use Utopia\Validator\Nullable; +use Utopia\Validator\Text; class Update extends Action { @@ -57,7 +57,7 @@ class Update extends Action contentType: ContentType::JSON )) ->param('tokenId', '', new UID(), 'Token unique ID.') - ->param('expire', null, new Nullable(new DatetimeValidator()), 'File token expiry date', true) + ->param('expire', null, new Text(100), 'File token expiry date', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') @@ -66,6 +66,13 @@ class Update extends Action public function action(string $tokenId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents) { + if (!is_null($expire)) { + $validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_DAYS, offset: 0); + if (!$validator->isValid($expire)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now'); + } + } + $token = $dbForProject->getDocument('resourceTokens', $tokenId); if ($token->isEmpty()) { diff --git a/tests/e2e/Services/Tokens/TokensConsoleClientTest.php b/tests/e2e/Services/Tokens/TokensConsoleClientTest.php index c0f94a55bf..ab3790abca 100644 --- a/tests/e2e/Services/Tokens/TokensConsoleClientTest.php +++ b/tests/e2e/Services/Tokens/TokensConsoleClientTest.php @@ -9,7 +9,6 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -63,10 +62,23 @@ class TokensConsoleClientTest extends Scope $fileId = $file['body']['$id']; + // Failure case: Expire date is in the past $token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders())); + ], $this->getHeaders()), [ + 'expire' => '2022-11-02', + ]); + $this->assertEquals(400, $token['headers']['status-code']); + $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + + // Success case: No expire date + $token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders()), [ + 'expire' => null, + ]); $this->assertEquals(201, $token['headers']['status-code']); $this->assertEquals('files', $token['body']['resourceType']); @@ -107,8 +119,19 @@ class TokensConsoleClientTest extends Scope { $tokenId = $data['tokenId']; + // Failure case: Expire date is in the past + $token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'expire' => '2022-11-02', + ]); + $this->assertEquals(400, $token['headers']['status-code']); + $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + // Finite expiry - $expiry = DateTime::addSeconds(new \DateTime(), 3600); + $expiry = date('Y-m-d', strtotime("tomorrow")); $token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'] diff --git a/tests/e2e/Services/Tokens/TokensCustomServerTest.php b/tests/e2e/Services/Tokens/TokensCustomServerTest.php index fe8fa2bad9..eaf30049f9 100644 --- a/tests/e2e/Services/Tokens/TokensCustomServerTest.php +++ b/tests/e2e/Services/Tokens/TokensCustomServerTest.php @@ -7,7 +7,6 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -61,6 +60,17 @@ class TokensCustomServerTest extends Scope $fileId = $file['body']['$id']; + // Failure case: Expire date is in the past + $token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders()), [ + 'expire' => '2022-11-02', + ]); + $this->assertEquals(400, $token['headers']['status-code']); + $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + + // Success case: No expire date $token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'] @@ -83,8 +93,19 @@ class TokensCustomServerTest extends Scope { $tokenId = $data['tokenId']; - // Finite expiry - $expiry = DateTime::addSeconds(new \DateTime(), 3600); + // Failure case: Expire date is in the past + $token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'expire' => '2022-11-02', + ]); + $this->assertEquals(400, $token['headers']['status-code']); + $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + + // Success case: Finite expiry + $expiry = date('Y-m-d', strtotime("tomorrow")); $token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -94,9 +115,10 @@ class TokensCustomServerTest extends Scope ]); $dateValidator = new DatetimeValidator(); + $this->assertEquals(200, $token['headers']['status-code']); $this->assertTrue($dateValidator->isValid($token['body']['expire'])); - // Infinite expiry + // Success case: Infinite expiry $token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], From 60e57eb9c59185ae6f83d5855cdbb0927870552b Mon Sep 17 00:00:00 2001 From: Hemachandar Date: Mon, 3 Nov 2025 17:29:48 +0530 Subject: [PATCH 072/167] lint --- .../Modules/Tokens/Http/Tokens/Buckets/Files/Create.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index 0d905838a7..aa06753420 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -76,7 +76,7 @@ class Create extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now'); } } - + /** * @var Document $bucket From df8fb23e75182fc20b6880b97311c634dd638390 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:13:21 +0000 Subject: [PATCH 073/167] Fix test assertion for file count with offset Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- tests/e2e/Services/Storage/StorageBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index 2012be7375..a89cd711cb 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -448,7 +448,7 @@ trait StorageBase ], ]); $this->assertEquals(200, $files['headers']['status-code']); - $this->assertEquals(0, count($files['body']['files'])); + $this->assertEquals(1, count($files['body']['files'])); $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'application/json', From 2d332264c67f5fc8bd8bddd3213fc79c6333f2c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 06:16:41 +0000 Subject: [PATCH 074/167] Replace with simple webp image for testing Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- tests/resources/logo-after.webp | Bin 6236 -> 634 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/resources/logo-after.webp b/tests/resources/logo-after.webp index b91c5dc1fa912333d58fba3f42bbce0f8559ae73..4a8791784a819b23d95ba2eef1de7fde040e3c9c 100644 GIT binary patch literal 634 zcmV-=0)_ojNk&F;0ssJ4MM6+kP&goF0ssJTAOM{KDv$wW06tM7k3}P*As3mv05}B% zv$t@!kcR;P{Xpv!@<7$3@yGRF!D+xBg?^|10Q?>O0N`ix0X_lbXZ!=i8X!NQdFB3@ z`~&#M_RsE}B>&XCP&$A=RZ5Gds?ur|MJru3R+CU6nxFeN>6BHzR~aLP!2Jh-Oj)OS zUTc+*>VRhxh#-3HF#M%evvD53)-#T$_?XU21=)c35Rr>47o8+2svO*!BE4hGj)15&1k5K zJFntgTznMm4pBQ{{K^81fgBPI$P`H;&vzh z{w6)I_+NkGcJ{-!^<|Uc5C5?1{_M?}{RrUj*_4jC`&}ex`zNVj9-;_Xa7F+NT;e^Wjb`{XDmxYC z%hCkeMpiZ<3^%-y|B&b74a!C5iC1PFI4iiOYUYiA_M0~o^3%=#7Z&_J(fWPJe>iJb UFbRwZDTesrE^7?y000000F0V5`2YX_ literal 6236 zcmV-i7^CM>Nk&Fg7ytlQMM6+kP&il$0000G0000R0RS5T06|PpNO=PQ00DPkrfu8c z+?{(zqY)AFN2O!~Qf%9L-sV}AW&o8cNKg?nl#D!qHi47@gh@=y2@{Kh-oI@8%iSm= z=)qOPaQVyk-FttlfQbIXaU;o*RAumlUok6QU?KLAY1z*WDYJdvkuraL+EC)LpY){Y zp44T`{_)M63}nm~zujp~h_?(y%x}NDle!G=(pTYq8VWqhn3Il#8<(}yhJy3&nJ6#^ z0cO*aqI*)Kzj1jC`OBF1?;5#E`0Yh@Qm3{EeP)Z%ATDDuI{Y^-Hw5(OKQ{zYbWa*W zWPRE4)ywR(Mt$QHgy4&NNeC?o^Z74WNn-gc`NzFH4YD$pr^9NAN>ZKw5cH(zp45p9 z!+@`h3PP}-se%xEaSsTI0pTiRkPwi`U&%l2O4vRMJSQC{1630K{D-E;W3Wns8=e72 z85M+JKT`!E`0XAEVB@fbZ}1Sn8jBa`H!ea5K+7194yI9oJpVE2VH>5AfW~EjTSf&T z*w2x_lD|FvPHJGrXA4#SO1{lJ{|Z8Ion(xJ5Nys|3kPaQLFmD7cpnj!?4mG$;RDLQ zVM6eH2Eq`AF$fc!f1iNRhhc<5WrbjwQ%N}?ST$5~sq?Z0he`@TA}0jP<4Uf|-(-8( zuvJl&+*}{6s_7%4Re2@lylfFu$$nK;a<=rVm&cV{=Df+)sHm4MpX7XjVbxH{RryCkRmDj)RkE>0TFJ2-7VwXR zmdKS{k-y2NhR0g?*)}Pa+%;43kN*0kk1cl_UaiT=C?n(ZQqpxJn`4IZ@x42L6-Lg>aNYV%KVo0 z*0%qW-$gV%kN+#~pXT49k1%i25BHvxUc-NHy+D4x{;zw!|E~3i{Cz;oPAk8#Q)djXX;=3|LQ&gKb!w$|Be0Q{9nH}uMghOV{h1UE8({~D`f1KdC<|! zu@p<#0Il+OXzV-|r{v=OY@L$tCmix-^oj3w>7KRRgK*mP;&o7o?46SCAuCw`6W}r^ zB3%p~hco$lxECtRZ~3ITYrOH;kD|6s{gWfFWtygWT%s#?#&;;3W1~}+w(}W^j z=S5IwW#IT3ve0SKO1BW(iepf+T3)toYU81!P7sNAoeq(sak3(m=Ft9V#*wK(>V^*PqOsdx20%Y$hAl$z(9x#|M7z$1 zD2p{9CtsrME?hlHye*<)8LXoEGn+mTcJmzPQrCIou^&Zh{8^xSTSe%f&BH+)Op<$^ z_TQC5U=KU#|JvB*aZ?i=hTQ0Kh_g}x9@5iD>~&G<-R))6N#LrW)b?BcE(;s7TKsWs~mMO+YdtEM+g5n zl2)`|GA=#ux!Ofu1=$J8$Rb4bek{;EEuQZ2S-gp@ld@gsLzH5~i`?vE*#7^20GC%8eI9U= z@%?N?MIezsghZn_y=QC`@7kZ%CTtda@I`i=8#HhnJ#_$7!xVV&Gp+PYvC&vbLNzLD2WJpe2J{FIlAA+0T^ zxX|v^e_aHH{}`(w?~8|`8Tb}hGdYIZSM3?t4MCG%{PbQUc8q%wMJaYMI<=Z)EkccW z*N<(D-}J}%vGv35WagA{X7MPbnZ>Z0)AMTfMJ+rr&hLjeA2gr0lh z{*zjFHP#@ZQ#()!%w1=UiabUR9T0TJ@ltvap^6$8(4;lmw7eSj7EQ?xoDd02M% zb2N+u#9AqMoYZ-zwMDd|1qWI}6S?>0L0T-Y+uxnKmCvAKEA`3KVGD{~aZ)Gg4phtR zYkGs!Nsi&-vd*(T)CRB^Bj|nBcwSD2b0Tq0*6jGv-e|j4y|fjM!5F8^<2ooNo#r2J zW+xT{G#Z>Df05cTB@f&rbzRf168Ubp^^F8(%~k5%f*M{4g(oZUUv_^CgMx)|zu~)v zN!obbh7KGoTVz;b><+65Pu}x7{Cn?QLeMzpA^>|RU9E`hf@f*4={F=nqP0dv2O?$}yt0ygxkt)zJ6gQFM$4S9$ zxY~T=k%$8!bNM0ea{ZJ+mua;SK-fiWnv6T|Kwx((FYbUG9v>M;Sc=aH_L|Gd4*xj3imzO2slyD z7e8dNeq%{gF5oN^2Iq^gdlMfhm`5e%gd((A1bO$nN}7A=PMqYK{TI6beu7AMS@a4( z*6f}oceOHm3s!`lPYc&^@r_Y^-G}gGdgV5}mO@?PsqHexdlN0<9ROo;`o4@m{|4s%sC=R+(M zhfoL@Me>7I2uFYa93K{Xh0oPG!HNCnPxnPEP;ggvY0*@_Ydl z3Io2EL@{)XXz%qPe3p$IT}c2^$ZUFMuXGtudL>V&%Pp&aj~0VWgAwcY_&lnzeUrrS zE;X0yNAcJF*`AJD!7f^Yg1AN^nBE`X8g3#wu4uBDj>XJKYUGK8VIza_ikdSsZci-! z>|Ju|7J)2LI;N=wvimZz^r^| zgW2EU)NiJs{K8(M#M0*fsUp2xcTVHCmn8z@k^7|Y|Kb^IMbL0AG;mAkAV7}jJ_OJP z{A$Q7{u~6AIz~6W!Fj)UBJcu0|NCmrlPJrxWLeg4NpG=V07_*i*ZtKQ668oVl|;16 zAeLT#r}Z6G*ufnpouQg){`O(wS9@}9W$82XS1)!!a4d?ck1bHRy%Rhhq1PNZd62RF zK?z3+q7`)UkGllyt^?7HwgbS~KMO9_Uqi$^uhn!jWjS-u+w25WqAj3H3EgJ;LEodU zKU{1|?KeH*Hs43sVr&BOVy6D(adsZrTq zKGJMNV>c8ER|-77k|tx2j!&j4T7q&|HyU;C^+b^(ao%H>$l9dUirByx9P2Ou+45S3 zzFDpQPu}?^vC3&&LP={Pl?6x|#Ae668Vf<{lZTWPpC4@rnYajhX~*t6PC8L6ny})P z4I`+2T=ASU2f}gXZ7oZ5>@aZQV%s9a7hrW*MUsE4wrk|)uETbe;%QcP?rs{+_qV|3irS#;V-0$P$bS4bOs z#D*aqFbH|`!#V8Cn0y%e`KHOI!$d6Wyn>}Zpe7Tnwq%}_y(#YI6Rj#=+Tb(hKFji= z6E$)3q+U(1@%a?5^aOl<9T(e=V#cknjK7irWJ(bWn22l~tYXnF7+vVM%22RPz|W8( zsylO$h24CS=sxfW8JQ|-oH3`L0{kYE5!QkeAXQcMTOE)}{o#A!AVM46@zwhVAM2_? z7Qh44f45o047Tv#D06v8W}Z$a%;x3mUMVva&@xk-ep!$I@il+{6kGrQ6K!RNF2L%r zisb)UY}d)pT~o%d#~OpCotl#i{@n^D4i3WSn2?Wq+FM#}1&g3lxN%aP=E)smY#`6f zv#6w5pq#;zb&led+f)1H^X(2`SC1d47CeH6&{wRiI3?SZrrgpLqPr+HG|#otJb3ur zv<0#OLc7 zLKdLLjCZs&$UH%^E_g!xENUA8+D@f$Z?gf-QIT(JSg9{+R?NJlfB{T~d7gB2bFLtgiW0rTaCI zC^&d?>t=8d)~EjrQ+lU135SYtIU7z@9S)bl*0k9PwIjUG&TLo@v_KK&C^Wdm*CQ{Hc@J#EeCz74@p}+Z%krc{FtJENESs96hf}r zQi}mhVXRA%dl;S)44z_Hc@g2GNkn;f7;eCoy>%7d@)@qp^mkbmSBeIGPyF+fl9f<; z^cGCZ!Stq~88X-*T1ASdj_>!{N4*nzh=w~A0S^SO+h9sNgUG40+q$vkquyYzlQV~Db1m6v9HI$lZ+M{m)`h@#B z=n{8|O>27W9Y31|L;8PC_qZZKHldtkr%nHxwxL1NPHg^g6iTTU9aYakFRrnckxIEO zXk-^ZE3Se&L)Zb8)b9V)O&*A+2$$uYzhx{3;RaYJ;3>(I3%DRRu=zMh$j@onhgWCT zmj?IcNC!&V;(Ym&v@~fa#fTUiMDsD!dx2(A#fQY?!l(x={2@ld%n+dzmnnp9$y!QL zZU(Y8MWeHZ7l>!`=rC-1`1t5Zj|?C`eVu>)$$9PeijsbcueiD0!~*KkycDn>yMOgu zY^|V{pr9UB@`bgKkiSqMwYCFBgUKn(Lzt1%FvAEsUeF!XqR-LsfEBJ>dhmL50QjKX zl+M$gsTA2aXjJW^?XO@S;r7D-SW|Z#_F&b3|An-gY*lNb%DaUtXbUplIOdcY%C6cto+5^!mRhQ2E$tkrIr(j%tx)AG97;_8t;9 zutw--y6f&ZfRK&i)huO3 zR?tuumnt047liVwBkNt;3Lr-R`HKzKY1$I7DZUC%_iE6+D{v~W=FEWoV>FU)P< zfuy7b37?)*I0~<_anKBKpGnaiDq-NX2{D8um#&|1P<8X8M&WdccG&;P9Pyko!s G0000WrY4pE From f0e4c9184d35729ab9137dc781054c3917063dc7 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 4 Nov 2025 16:44:09 +0200 Subject: [PATCH 075/167] Update composer.json and composer.lock to reflect new version constraints for utopia-php/audit and utopia-php/database, ensuring compatibility with the latest releases. Adjusted versioning for utopia-php/migration and appwrite/sdk-generator to their respective latest versions. --- composer.json | 4 +-- composer.lock | 74 ++++++++++++++++++++------------------------------- 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/composer.json b/composer.json index 42194d664d..b4850aaaca 100644 --- a/composer.json +++ b/composer.json @@ -47,11 +47,11 @@ "appwrite/php-clamav": "2.0.*", "utopia-php/abuse": "1.*", "utopia-php/analytics": "0.10.*", - "utopia-php/audit": "dev-feat-auth-single-instance as 1.1.0", + "utopia-php/audit": "1.*", "utopia-php/cache": "0.13.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-feat-authorization-instance as 3.0.2", + "utopia-php/database": "4.*", "utopia-php/detector": "0.2.*", "utopia-php/domains": "0.9.*", "utopia-php/emails": "0.6.*", diff --git a/composer.lock b/composer.lock index 1f10c437cf..dc3dc2407e 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": "881b001010468bad06d1eef0693e8ed0", + "content-hash": "550f8ddb2f6c846a6476916ca35fb1c6", "packages": [ { "name": "adhocore/jwt", @@ -3547,21 +3547,21 @@ }, { "name": "utopia-php/audit", - "version": "dev-feat-auth-single-instance", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "b74a6f8213b444e0af6ce0714ec85ea2859b3508" + "reference": "15656acfddb9d6f03c395b73673fc66c793c10a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/b74a6f8213b444e0af6ce0714ec85ea2859b3508", - "reference": "b74a6f8213b444e0af6ce0714ec85ea2859b3508", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/15656acfddb9d6f03c395b73673fc66c793c10a5", + "reference": "15656acfddb9d6f03c395b73673fc66c793c10a5", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "dev-feat-authorization-instance as 3.0.2" + "utopia-php/database": "4.*" }, "require-dev": { "laravel/pint": "1.*", @@ -3588,9 +3588,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/feat-auth-single-instance" + "source": "https://github.com/utopia-php/audit/tree/1.0.3" }, - "time": "2025-10-27T13:39:14+00:00" + "time": "2025-11-04T11:27:42+00:00" }, { "name": "utopia-php/cache", @@ -3840,16 +3840,16 @@ }, { "name": "utopia-php/database", - "version": "dev-feat-authorization-instance", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "5464da0f13d159096b1ee62acfddf0440be36596" + "reference": "da9d021b2722abdf4df08a739126f1be2707cf6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/5464da0f13d159096b1ee62acfddf0440be36596", - "reference": "5464da0f13d159096b1ee62acfddf0440be36596", + "url": "https://api.github.com/repos/utopia-php/database/zipball/da9d021b2722abdf4df08a739126f1be2707cf6d", + "reference": "da9d021b2722abdf4df08a739126f1be2707cf6d", "shasum": "" }, "require": { @@ -3922,10 +3922,10 @@ "utopia" ], "support": { - "source": "https://github.com/utopia-php/database/tree/feat-authorization-instance", + "source": "https://github.com/utopia-php/database/tree/4.0.0", "issues": "https://github.com/utopia-php/database/issues" }, - "time": "2025-11-03T10:08:55+00:00" + "time": "2025-11-04T10:55:46+00:00" }, { "name": "utopia-php/detector", @@ -4514,16 +4514,16 @@ }, { "name": "utopia-php/migration", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c" + "reference": "81e1be6ff3257d4768aa7483cf64628836244a09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/731b3a963c58c30e0b2368695d57a7e8fcb7455c", - "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/81e1be6ff3257d4768aa7483cf64628836244a09", + "reference": "81e1be6ff3257d4768aa7483cf64628836244a09", "shasum": "" }, "require": { @@ -4532,7 +4532,7 @@ "ext-openssl": "*", "php": ">=8.1", "utopia-php/console": "0.0.*", - "utopia-php/database": "3.*", + "utopia-php/database": "4.*", "utopia-php/dsn": "0.2.*", "utopia-php/storage": "0.18.*" }, @@ -4580,10 +4580,10 @@ "utopia" ], "support": { - "source": "https://github.com/utopia-php/migration/tree/1.3.3", + "source": "https://github.com/utopia-php/migration/tree/1.3.4", "issues": "https://github.com/utopia-php/migration/issues" }, - "time": "2025-10-28T04:02:08+00:00" + "time": "2025-11-04T11:28:50+00:00" }, { "name": "utopia-php/mongo", @@ -5468,16 +5468,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "42df22195d6457e52e4c819678168470b114a816" + "reference": "cd712674e34136f706e9170641ed6f4ce160e772" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/42df22195d6457e52e4c819678168470b114a816", - "reference": "42df22195d6457e52e4c819678168470b114a816", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cd712674e34136f706e9170641ed6f4ce160e772", + "reference": "cd712674e34136f706e9170641ed6f4ce160e772", "shasum": "" }, "require": { @@ -5513,9 +5513,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.5.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.1" }, - "time": "2025-10-31T10:10:25+00:00" + "time": "2025-11-04T09:55:47+00:00" }, { "name": "doctrine/annotations", @@ -8980,25 +8980,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/audit", - "version": "dev-feat-auth-single-instance", - "alias": "1.1.0", - "alias_normalized": "1.1.0.0" - }, - { - "package": "utopia-php/database", - "version": "dev-feat-authorization-instance", - "alias": "3.0.2", - "alias_normalized": "3.0.2.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/audit": 20, - "utopia-php/database": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From f3fd2fd1910d879b715dd4bddd466271e7537c89 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 4 Nov 2025 17:11:45 +0200 Subject: [PATCH 076/167] composer.lock --- composer.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.lock b/composer.lock index 16301dffa6..560f311036 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": "550f8ddb2f6c846a6476916ca35fb1c6", + "content-hash": "352d5b81626632665fbc8e3e76a1b950", "packages": [ { "name": "adhocore/jwt", @@ -3457,7 +3457,7 @@ "reference": "611fa66a97e87c0dbbc133a717d970da7a5ca828" }, "dist": { - "type": "zip",\ + "type": "zip", "url": "https://api.github.com/repos/utopia-php/abuse/zipball/611fa66a97e87c0dbbc133a717d970da7a5ca828", "reference": "611fa66a97e87c0dbbc133a717d970da7a5ca828", "shasum": "" @@ -8981,7 +8981,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From fe9d49c3465b803769773a20cf4cad97cf0e748d Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 4 Nov 2025 17:13:53 +0200 Subject: [PATCH 077/167] Response Model --- src/Appwrite/Utopia/Response/Model/User.php | 30 +++++++++++++++++++++ tests/e2e/Services/Account/AccountBase.php | 4 ++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index 672b8885a0..c9ec5e36bc 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -139,6 +139,36 @@ class User extends Model 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) + ->addRule('emailCanonical', [ + 'type' => self::TYPE_STRING, + 'description' => 'User email address.', + 'default' => null, + 'example' => 'john@appwrite.io', + ]) + ->addRule('emailIsCanonical', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'User email is canonical.', + 'default' => null, + 'example' => true, + ]) + ->addRule('emailIsCorporate', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'User email is corporate.', + 'default' => null, + 'example' => true, + ]) + ->addRule('emailIsDisposable', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'User email is disposable.', + 'default' => null, + 'example' => true, + ]) + ->addRule('emailIsFree', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'User email is free.', + 'default' => null, + 'example' => true, + ]) ; } diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index b2f85637a8..d51632c6c9 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -29,7 +29,7 @@ trait AccountBase ]); $id = $response['body']['$id']; - + var_dump($response['body']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']); $this->assertNotEmpty($response['body']['$id']); @@ -41,6 +41,8 @@ trait AccountBase $this->assertNotEmpty($response['body']['accessedAt']); $this->assertArrayHasKey('targets', $response['body']); $this->assertEquals($email, $response['body']['targets'][0]['identifier']); + $this->assertEquals('shmuel', 'fogel'); + /** * Test for FAILURE From 501cba216b010b74f2197334fc1558cccb935d0c Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 5 Nov 2025 16:09:20 +1300 Subject: [PATCH 078/167] Update app/init/resources.php --- app/init/resources.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/init/resources.php b/app/init/resources.php index db2cc093f0..8b111e950c 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -485,7 +485,6 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); - $database->setAuthorization($authorization); $databases[$dsn->getHost()] = $database; $configure($database); From 1f0e3e0f51bd8f166e50ae2aa8386077ba67099a Mon Sep 17 00:00:00 2001 From: fogelito Date: Wed, 5 Nov 2025 13:21:52 +0200 Subject: [PATCH 079/167] lock file --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 394e2a9e3e..c950ec5492 100644 --- a/composer.lock +++ b/composer.lock @@ -3840,16 +3840,16 @@ }, { "name": "utopia-php/database", - "version": "3.1.2", + "version": "3.1.3", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "b6541a9cd9b21786a5020327f582838afdb159aa" + "reference": "b38cc9887a8fefedcb9a962168dd6f28b7082fc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b6541a9cd9b21786a5020327f582838afdb159aa", - "reference": "b6541a9cd9b21786a5020327f582838afdb159aa", + "url": "https://api.github.com/repos/utopia-php/database/zipball/b38cc9887a8fefedcb9a962168dd6f28b7082fc1", + "reference": "b38cc9887a8fefedcb9a962168dd6f28b7082fc1", "shasum": "" }, "require": { @@ -3892,9 +3892,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.1.2" + "source": "https://github.com/utopia-php/database/tree/3.1.3" }, - "time": "2025-10-30T13:10:13+00:00" + "time": "2025-11-04T11:41:54+00:00" }, { "name": "utopia-php/detector", @@ -5378,16 +5378,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "42df22195d6457e52e4c819678168470b114a816" + "reference": "cd712674e34136f706e9170641ed6f4ce160e772" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/42df22195d6457e52e4c819678168470b114a816", - "reference": "42df22195d6457e52e4c819678168470b114a816", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cd712674e34136f706e9170641ed6f4ce160e772", + "reference": "cd712674e34136f706e9170641ed6f4ce160e772", "shasum": "" }, "require": { @@ -5423,9 +5423,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.5.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.1" }, - "time": "2025-10-31T10:10:25+00:00" + "time": "2025-11-04T09:55:47+00:00" }, { "name": "doctrine/annotations", From 8a9d0a3f337f3230a33d16259186d48eb43dc0e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 19:30:21 +0000 Subject: [PATCH 080/167] Rename logo-after.webp to image.webp Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- tests/e2e/Services/Storage/StorageBase.php | 4 ++-- tests/resources/{logo-after.webp => image.webp} | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/resources/{logo-after.webp => image.webp} (100%) diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index a89cd711cb..c67cfcc99a 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -271,7 +271,7 @@ trait StorageBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo-after.webp'), 'image/webp', 'logo-after.webp'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/image.webp'), 'image/webp', 'image.webp'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -280,7 +280,7 @@ trait StorageBase ]); $this->assertEquals(201, $webpFile['headers']['status-code']); $this->assertNotEmpty($webpFile['body']['$id']); - $this->assertEquals('logo-after.webp', $webpFile['body']['name']); + $this->assertEquals('image.webp', $webpFile['body']['name']); $this->assertEquals('image/webp', $webpFile['body']['mimeType']); $webpFileId = $webpFile['body']['$id']; diff --git a/tests/resources/logo-after.webp b/tests/resources/image.webp similarity index 100% rename from tests/resources/logo-after.webp rename to tests/resources/image.webp From 16d6c9e5e310723ead25fda72557c9ee451be049 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 6 Nov 2025 16:11:57 +0200 Subject: [PATCH 081/167] debug dbHelth --- tests/e2e/Services/Health/HealthCustomServerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 4b7062dc22..7f7621f1c7 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -40,7 +40,7 @@ class HealthCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); - + var_dump($response); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('pass', $response['body']['statuses'][0]['status']); $this->assertIsInt($response['body']['statuses'][0]['ping']); From d0f2293755e14b26ae9be48692c9ad67188c46e1 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 6 Nov 2025 16:42:58 +0200 Subject: [PATCH 082/167] debug health db --- app/controllers/api/health.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 765688e1ee..a411002532 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -132,8 +132,9 @@ App::get('/v1/health/db') } if (!empty($failures)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failures)); - } + $output= $failures; + //throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failures)); + } $response->dynamic(new Document([ 'statuses' => $output, From 3d471bae5618bfc8cd62ff6c3ef36f442de46d3c Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 6 Nov 2025 17:37:31 +0200 Subject: [PATCH 083/167] health db debug --- app/controllers/api/health.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index a411002532..765688e1ee 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -132,9 +132,8 @@ App::get('/v1/health/db') } if (!empty($failures)) { - $output= $failures; - //throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failures)); - } + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failures)); + } $response->dynamic(new Document([ 'statuses' => $output, From ae2ffd259ca524d9a65b771e5dcb71269207f907 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 6 Nov 2025 17:54:44 +0200 Subject: [PATCH 084/167] Remove debug output from HealthCustomServerTest --- tests/e2e/Services/Health/HealthCustomServerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 7f7621f1c7..63516f624d 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -40,7 +40,6 @@ class HealthCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); - var_dump($response); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('pass', $response['body']['statuses'][0]['status']); $this->assertIsInt($response['body']['statuses'][0]['ping']); From 7c408d675ea258f202eac6d9090447f912afde64 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 7 Nov 2025 14:30:22 +0530 Subject: [PATCH 085/167] pr followups --- app/config/collections/projects.php | 2 +- src/Appwrite/Migration/Version/V23.php | 49 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/app/config/collections/projects.php b/app/config/collections/projects.php index c7205c667d..dae0337dc9 100644 --- a/app/config/collections/projects.php +++ b/app/config/collections/projects.php @@ -2345,7 +2345,7 @@ return [ '$id' => ID::custom('errors'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 131070, + 'size' => 1_000_000, 'signed' => true, 'required' => true, 'default' => null, diff --git a/src/Appwrite/Migration/Version/V23.php b/src/Appwrite/Migration/Version/V23.php index f9fd63346f..a4027b506e 100644 --- a/src/Appwrite/Migration/Version/V23.php +++ b/src/Appwrite/Migration/Version/V23.php @@ -133,6 +133,13 @@ class V23 extends Migration } $this->dbForProject->purgeCachedCollection($id); break; + case 'migrations': + try { + $this->updateMigrateErrorSize(); + } catch (\Throwable $th) { + Console::warning("Failed to migration error attribute size in collection {$id}: {$th->getMessage()}"); + } + default: break; } @@ -202,4 +209,46 @@ class V23 extends Migration } return $document; } + + /** + * Update migration attribute size + * @return void + */ + private function updateMigrateErrorSize(): void + { + + if ($this->project->getId() === 'console') { + return; + } + + // Read-modify-write from the live schema to avoid overwriting unrelated changes. + $migration = $this->dbForProject->getCollection('migrations'); + $attributes = $migration->getAttribute('attributes', []); + $attrsArray = \array_map(fn (Document $doc) => $doc->getArrayCopy(), $attributes); + $errorsIdx = \array_search('errors', \array_column($attrsArray, '$id')); + + if ($errorsIdx === false) { + Console::warning("Skipping: 'errors' attribute not found in migrations collection for project {$this->project->getId()}"); + return; + } + + $desiredSize = 1_000_000; + $migrationAttributes = Config::getParam('collections', [])['projects']['migrations']['attributes'] ?? []; + $migrationIndex = \array_search('errors', \array_column($migrationAttributes, '$id')); + + if ($migrationIndex !== false && isset($migrationAttributes[$migrationIndex]['size'])) { + $desiredSize = (int) $migrationAttributes[$migrationIndex]['size']; + } + + $currentSize = (int) ($attributes[$errorsIdx]['size'] ?? 0); + + if ($currentSize === $desiredSize) { + Console::warning("Skipping: 'errors' attribute already of desired size {$desiredSize} in migrations collection for project {$this->project->getId()}"); + return; + } + $attributes[$errorsIdx]['size'] = $desiredSize; + $migration->setAttribute('attributes', $attributes); + $this->dbForProject->updateDocument($migration->getCollection(), $migration->getId(), $migration); + $this->dbForProject->purgeCachedCollection('migrations'); + } } From eb0e42b79cb02a9c034a33688f471e5419cfe8e9 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Sun, 9 Nov 2025 12:13:08 +0530 Subject: [PATCH 086/167] added error message for the backups route --- app/controllers/shared/api.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 122139d48b..2d32c906bf 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -234,7 +234,9 @@ App::init() ->inject('apiKey') ->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey) { $route = $utopia->getRoute(); - + if (System::getEnv('_APP_EDITION', 'self-hosted') === 'self-hosted' && str_starts_with($route->getPath(), '/v1/backups')) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Database Backups are available on Appwrite Cloud'); + } if ($project->isEmpty()) { throw new Exception(Exception::PROJECT_NOT_FOUND); } From 3ef6154ebe7065154ad168015855ea0b3b910d3d Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 9 Nov 2025 10:10:22 +0200 Subject: [PATCH 087/167] Update composer.lock to reflect package version upgrades and dependency changes, including Symfony components and Utopia PHP libraries. --- composer.lock | 132 ++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/composer.lock b/composer.lock index f00d089566..957969c639 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": "352d5b81626632665fbc8e3e76a1b950", + "content-hash": "3b502f78f5e31f2ea7b4c69e3301283a", "packages": [ { "name": "adhocore/jwt", @@ -2673,16 +2673,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.4", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", "shasum": "" }, "require": { @@ -2749,7 +2749,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "source": "https://github.com/symfony/http-client/tree/v7.3.6" }, "funding": [ { @@ -2769,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-11-05T17:41:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -3176,16 +3176,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -3239,7 +3239,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -3250,12 +3250,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "tbachert/spi", @@ -3840,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "4.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "da9d021b2722abdf4df08a739126f1be2707cf6d" + "reference": "c34cb23844944ebda952d0f2390bc9d0285f8c12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/da9d021b2722abdf4df08a739126f1be2707cf6d", - "reference": "da9d021b2722abdf4df08a739126f1be2707cf6d", + "url": "https://api.github.com/repos/utopia-php/database/zipball/c34cb23844944ebda952d0f2390bc9d0285f8c12", + "reference": "c34cb23844944ebda952d0f2390bc9d0285f8c12", "shasum": "" }, "require": { @@ -3891,10 +3895,10 @@ "utopia" ], "support": { - "source": "https://github.com/utopia-php/database/tree/4.0.0", - "issues": "https://github.com/utopia-php/database/issues" + "issues": "https://github.com/utopia-php/database/issues", + "source": "https://github.com/utopia-php/database/tree/4.0.1" }, - "time": "2025-11-04T10:55:46+00:00" + "time": "2025-11-05T03:39:09+00:00" }, { "name": "utopia-php/detector", @@ -3943,22 +3947,24 @@ }, { "name": "utopia-php/dns", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/utopia-php/dns.git", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a" + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/dns/zipball/d6eca184883262bdcb4261e57491c91b16079b9a", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a", + "url": "https://api.github.com/repos/utopia-php/dns/zipball/1e6b4bac735329c9e5ec69a6a5d899ec2d050707", + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707", "shasum": "" }, "require": { "php": ">=8.3", "utopia-php/console": "0.0.*", - "utopia-php/telemetry": "0.1.*" + "utopia-php/domains": "0.9.*", + "utopia-php/telemetry": "0.1.*", + "utopia-php/validators": "^0.0.2" }, "require-dev": { "laravel/pint": "1.25.*", @@ -3992,9 +3998,9 @@ ], "support": { "issues": "https://github.com/utopia-php/dns/issues", - "source": "https://github.com/utopia-php/dns/tree/1.1.0" + "source": "https://github.com/utopia-php/dns/tree/1.1.3" }, - "time": "2025-11-03T22:49:02+00:00" + "time": "2025-11-06T19:08:29+00:00" }, { "name": "utopia-php/domains", @@ -4502,8 +4508,8 @@ "utopia" ], "support": { - "source": "https://github.com/utopia-php/migration/tree/1.3.4", - "issues": "https://github.com/utopia-php/migration/issues" + "issues": "https://github.com/utopia-php/migration/issues", + "source": "https://github.com/utopia-php/migration/tree/1.3.4" }, "time": "2025-11-04T11:28:50+00:00" }, @@ -6077,24 +6083,24 @@ }, { "name": "phpbench/container", - "version": "2.2.2", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/phpbench/container.git", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33" + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", "shasum": "" }, "require": { "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0" + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", + "php-cs-fixer/shim": "^3.89", "phpstan/phpstan": "^0.12.52", "phpunit/phpunit": "^8" }, @@ -6122,22 +6128,22 @@ "description": "Simple, configurable, service container.", "support": { "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.2" + "source": "https://github.com/phpbench/container/tree/2.2.3" }, - "time": "2023-10-30T13:38:26+00:00" + "time": "2025-11-06T09:05:13+00:00" }, { "name": "phpbench/phpbench", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878", + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878", "shasum": "" }, "require": { @@ -6152,26 +6158,26 @@ "phpbench/container": "^2.2", "psr/log": "^1.1 || ^2.0 || ^3.0", "seld/jsonlint": "^1.1", - "symfony/console": "^6.1 || ^7.0", - "symfony/filesystem": "^6.1 || ^7.0", - "symfony/finder": "^6.1 || ^7.0", - "symfony/options-resolver": "^6.1 || ^7.0", - "symfony/process": "^6.1 || ^7.0", + "symfony/console": "^6.1 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.1 || ^7.0 || ^8.0", + "symfony/finder": "^6.1 || ^7.0 || ^8.0", + "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0", + "symfony/process": "^6.1 || ^7.0 || ^8.0", "webmozart/glob": "^4.6" }, "require-dev": { "dantleech/invoke": "^2.0", "ergebnis/composer-normalize": "^2.39", - "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", + "php-cs-fixer/shim": "^3.9", "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^10.4 || ^11.0", "rector/rector": "^1.2", - "symfony/error-handler": "^6.1 || ^7.0", - "symfony/var-dumper": "^6.1 || ^7.0" + "symfony/error-handler": "^6.1 || ^7.0 || ^8.0", + "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0" }, "suggest": { "ext-xdebug": "For Xdebug profiling extension." @@ -6214,7 +6220,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.2" + "source": "https://github.com/phpbench/phpbench/tree/1.4.3" }, "funding": [ { @@ -6222,7 +6228,7 @@ "type": "github" } ], - "time": "2025-10-26T14:21:59+00:00" + "time": "2025-11-06T19:07:31+00:00" }, { "name": "phpstan/phpstan", @@ -7871,16 +7877,16 @@ }, { "name": "symfony/console", - "version": "v7.3.5", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", "shasum": "" }, "require": { @@ -7945,7 +7951,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.5" + "source": "https://github.com/symfony/console/tree/v7.3.6" }, "funding": [ { @@ -7965,20 +7971,20 @@ "type": "tidelift" } ], - "time": "2025-10-14T15:46:26+00:00" + "time": "2025-11-04T01:21:42+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.2", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", "shasum": "" }, "require": { @@ -8015,7 +8021,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" }, "funding": [ { @@ -8035,7 +8041,7 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:47+00:00" + "time": "2025-11-05T09:52:27+00:00" }, { "name": "symfony/finder", From eb17ffd5d28f42501a677e9309fb460d257e9a7a Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 10 Nov 2025 10:15:49 +0530 Subject: [PATCH 088/167] wrap all optional values with default null with nullable --- app/controllers/api/messaging.php | 141 +++++++++--------- app/controllers/api/project.php | 5 +- app/controllers/api/projects.php | 15 +- app/controllers/api/storage.php | 11 +- app/controllers/api/users.php | 5 +- .../Collections/Attributes/Boolean/Create.php | 3 +- .../Collections/Attributes/Boolean/Update.php | 2 +- .../Attributes/Datetime/Update.php | 2 +- .../Collections/Attributes/Email/Create.php | 3 +- .../Collections/Attributes/Email/Update.php | 2 +- .../Collections/Attributes/Enum/Create.php | 3 +- .../Collections/Attributes/Enum/Update.php | 2 +- .../Collections/Attributes/Float/Create.php | 7 +- .../Collections/Attributes/Float/Update.php | 6 +- .../Collections/Attributes/IP/Create.php | 3 +- .../Collections/Attributes/IP/Update.php | 2 +- .../Collections/Attributes/Integer/Create.php | 7 +- .../Collections/Attributes/Integer/Update.php | 6 +- .../Collections/Attributes/Line/Update.php | 2 +- .../Collections/Attributes/Point/Update.php | 2 +- .../Collections/Attributes/Polygon/Update.php | 2 +- .../Attributes/Relationship/Create.php | 5 +- .../Attributes/Relationship/Update.php | 7 +- .../Collections/Attributes/String/Create.php | 3 +- .../Collections/Attributes/String/Update.php | 4 +- .../Collections/Attributes/URL/Create.php | 3 +- .../Collections/Attributes/URL/Update.php | 2 +- .../Http/Databases/Collections/Create.php | 3 +- .../Documents/Attribute/Decrement.php | 5 +- .../Documents/Attribute/Increment.php | 5 +- .../Collections/Documents/Bulk/Delete.php | 3 +- .../Collections/Documents/Bulk/Update.php | 3 +- .../Collections/Documents/Bulk/Upsert.php | 3 +- .../Collections/Documents/Create.php | 5 +- .../Collections/Documents/Delete.php | 2 +- .../Databases/Collections/Documents/Get.php | 3 +- .../Collections/Documents/Update.php | 5 +- .../Collections/Documents/Upsert.php | 5 +- .../Databases/Collections/Documents/XList.php | 3 +- .../Http/Databases/Collections/Update.php | 3 +- .../Tables/Columns/Boolean/Create.php | 3 +- .../Tables/Columns/Boolean/Update.php | 2 +- .../Tables/Columns/Datetime/Update.php | 2 +- .../TablesDB/Tables/Columns/Email/Create.php | 3 +- .../TablesDB/Tables/Columns/Email/Update.php | 2 +- .../TablesDB/Tables/Columns/Enum/Create.php | 3 +- .../TablesDB/Tables/Columns/Enum/Update.php | 2 +- .../TablesDB/Tables/Columns/Float/Create.php | 7 +- .../TablesDB/Tables/Columns/Float/Update.php | 6 +- .../TablesDB/Tables/Columns/IP/Create.php | 3 +- .../TablesDB/Tables/Columns/IP/Update.php | 2 +- .../Tables/Columns/Integer/Create.php | 7 +- .../Tables/Columns/Integer/Update.php | 6 +- .../TablesDB/Tables/Columns/Line/Update.php | 2 +- .../TablesDB/Tables/Columns/Point/Update.php | 2 +- .../Tables/Columns/Polygon/Update.php | 2 +- .../Tables/Columns/Relationship/Create.php | 5 +- .../Tables/Columns/Relationship/Update.php | 7 +- .../TablesDB/Tables/Columns/String/Create.php | 3 +- .../TablesDB/Tables/Columns/String/Update.php | 4 +- .../TablesDB/Tables/Columns/URL/Create.php | 3 +- .../TablesDB/Tables/Columns/URL/Update.php | 2 +- .../Databases/Http/TablesDB/Tables/Create.php | 3 +- .../Http/TablesDB/Tables/Rows/Bulk/Delete.php | 3 +- .../Http/TablesDB/Tables/Rows/Bulk/Update.php | 3 +- .../Http/TablesDB/Tables/Rows/Bulk/Upsert.php | 3 +- .../TablesDB/Tables/Rows/Column/Decrement.php | 5 +- .../TablesDB/Tables/Rows/Column/Increment.php | 5 +- .../Http/TablesDB/Tables/Rows/Create.php | 5 +- .../Http/TablesDB/Tables/Rows/Delete.php | 2 +- .../Http/TablesDB/Tables/Rows/Get.php | 3 +- .../Http/TablesDB/Tables/Rows/Update.php | 5 +- .../Http/TablesDB/Tables/Rows/Upsert.php | 5 +- .../Http/TablesDB/Tables/Rows/XList.php | 3 +- .../Databases/Http/TablesDB/Tables/Update.php | 3 +- .../Functions/Http/Deployments/Create.php | 5 +- .../Functions/Http/Executions/Create.php | 3 +- .../Functions/Http/Variables/Update.php | 5 +- .../Modules/Sites/Http/Deployments/Create.php | 7 +- .../Modules/Sites/Http/Variables/Update.php | 5 +- 80 files changed, 254 insertions(+), 200 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 5193d0b30f..58a0ffe42f 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -49,6 +49,7 @@ use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\Integer; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -80,12 +81,12 @@ App::post('/v1/messaging/providers/mailgun') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) - ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) + ->param('isEuRegion', null, new Nullable(new Boolean()), 'Set as EU region.', true) ->param('fromName', '', new Text(128, 0), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.', true) ->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -177,7 +178,7 @@ App::post('/v1/messaging/providers/sendgrid') ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true) ->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -259,7 +260,7 @@ App::post('/v1/messaging/providers/resend') ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true) ->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -366,7 +367,7 @@ App::post('/v1/messaging/providers/smtp') ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true) ->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -453,7 +454,7 @@ App::post('/v1/messaging/providers/msg91') ->param('templateId', '', new Text(0), 'Msg91 template ID', true) ->param('senderId', '', new Text(0), 'Msg91 sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 auth key.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -536,7 +537,7 @@ App::post('/v1/messaging/providers/telesign') ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('customerId', '', new Text(0), 'Telesign customer ID.', true) ->param('apiKey', '', new Text(0), 'Telesign API key.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -620,7 +621,7 @@ App::post('/v1/messaging/providers/textmagic') ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -704,7 +705,7 @@ App::post('/v1/messaging/providers/twilio') ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true) ->param('authToken', '', new Text(0), 'Twilio authentication token.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -788,7 +789,7 @@ App::post('/v1/messaging/providers/vonage') ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -888,8 +889,8 @@ App::post('/v1/messaging/providers/fcm') ]) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('serviceAccountJSON', null, new JSON(), 'FCM service account JSON.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('serviceAccountJSON', null, new Nullable(new JSON()), 'FCM service account JSON.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -982,7 +983,7 @@ App::post('/v1/messaging/providers/apns') ->param('teamId', '', new Text(0), 'APNS team ID.', true) ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) ->param('sandbox', false, new Boolean(), 'Use APNS sandbox environment.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -1270,8 +1271,8 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) - ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('isEuRegion', null, new Nullable(new Boolean()), 'Set as EU region.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('fromName', '', new Text(128), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name.', true) @@ -1381,7 +1382,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('fromName', '', new Text(128), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) @@ -1479,7 +1480,7 @@ App::patch('/v1/messaging/providers/resend/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Resend API key.', true) ->param('fromName', '', new Text(128), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) @@ -1597,17 +1598,17 @@ App::patch('/v1/messaging/providers/smtp/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as `smtp1.example.com:25;smtp2.example.com`. You can also specify encryption type, for example: `tls://smtp1.example.com:587;ssl://smtp2.example.com:465"`. Hosts will be tried in order.', true) - ->param('port', null, new Range(1, 65535), 'SMTP port.', true) + ->param('port', null, new Nullable(new Range(1, 65535)), 'SMTP port.', true) ->param('username', '', new Text(0), 'Authentication username.', true) ->param('password', '', new Text(0), 'Authentication password.', true) ->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be \'ssl\' or \'tls\'', true) - ->param('autoTLS', null, new Boolean(), 'Enable SMTP AutoTLS feature.', true) + ->param('autoTLS', null, new Nullable(new Boolean()), 'Enable SMTP AutoTLS feature.', true) ->param('mailer', '', new Text(0), 'The value to use for the X-Mailer header.', true) ->param('fromName', '', new Text(128), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -1725,7 +1726,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('templateId', '', new Text(0), 'Msg91 template ID.', true) ->param('senderId', '', new Text(0), 'Msg91 sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 auth key.', true) @@ -1812,7 +1813,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('customerId', '', new Text(0), 'Telesign customer ID.', true) ->param('apiKey', '', new Text(0), 'Telesign API key.', true) ->param('from', '', new Text(256), 'Sender number.', true) @@ -1901,7 +1902,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->param('from', '', new Text(256), 'Sender number.', true) @@ -1990,7 +1991,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true) ->param('authToken', '', new Text(0), 'Twilio authentication token.', true) ->param('from', '', new Text(256), 'Sender number.', true) @@ -2079,7 +2080,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId') )) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->param('from', '', new Text(256), 'Sender number.', true) @@ -2187,8 +2188,8 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ]) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('serviceAccountJSON', null, new JSON(), 'FCM service account JSON.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) + ->param('serviceAccountJSON', null, new Nullable(new JSON()), 'FCM service account JSON.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -2282,12 +2283,12 @@ App::patch('/v1/messaging/providers/apns/:providerId') ]) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) ->param('teamId', '', new Text(0), 'APNS team ID.', true) ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) - ->param('sandbox', null, new Boolean(), 'Use APNS sandbox environment.', true) + ->param('sandbox', null, new Nullable(new Boolean()), 'Use APNS sandbox environment.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -2676,8 +2677,8 @@ App::patch('/v1/messaging/topics/:topicId') ] )) ->param('topicId', '', new UID(), 'Topic ID.') - ->param('name', null, new Text(128), 'Topic Name.', true) - ->param('subscribe', null, new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) + ->param('name', null, new Nullable(new Text(128)), 'Topic Name.', true) + ->param('subscribe', null, new Nullable(new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -3190,7 +3191,7 @@ App::post('/v1/messaging/messages/email') ->param('attachments', [], new ArrayList(new CompoundUID()), 'Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :.', true) ->param('draft', false, new Boolean(), 'Is message a draft', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('dbForPlatform') @@ -3363,7 +3364,7 @@ App::post('/v1/messaging/messages/sms') ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('draft', false, new Boolean(), 'Is message a draft', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('dbForPlatform') @@ -3486,7 +3487,7 @@ App::post('/v1/messaging/messages/push') ->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true) ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) - ->param('data', null, new JSON(), 'Additional key-value pair data for push notification.', true) + ->param('data', null, new Nullable(new JSON()), 'Additional key-value pair data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) ->param('image', '', new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as :.', true) ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) @@ -3495,7 +3496,7 @@ App::post('/v1/messaging/messages/push') ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', -1, new Integer(), 'Badge for push notification. Available only for iOS Platform.', true) ->param('draft', false, new Boolean(), 'Is message a draft', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->param('contentAvailable', false, new Boolean(), 'If set to true, the notification will be delivered in the background. Available only for iOS Platform.', true) ->param('critical', false, new Boolean(), 'If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.', true) ->param('priority', 'high', new WhiteList(['normal', 'high']), 'Set the notification priority. "normal" will consider device state and may not deliver notifications immediately. "high" will always attempt to immediately deliver the notification.', true) @@ -3981,17 +3982,17 @@ App::patch('/v1/messaging/messages/email/:messageId') ] )) ->param('messageId', '', new UID(), 'Message ID.') - ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) - ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) - ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) - ->param('subject', null, new Text(998), 'Email Subject.', true) - ->param('content', null, new Text(64230), 'Email Content.', true) - ->param('draft', null, new Boolean(), 'Is message a draft', true) - ->param('html', null, new Boolean(), 'Is content of type HTML', true) - ->param('cc', null, new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true) - ->param('bcc', null, new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) - ->param('attachments', null, new ArrayList(new CompoundUID()), 'Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :.', true) + ->param('topics', null, new Nullable(new ArrayList(new UID())), 'List of Topic IDs.', true) + ->param('users', null, new Nullable(new ArrayList(new UID())), 'List of User IDs.', true) + ->param('targets', null, new Nullable(new ArrayList(new UID())), 'List of Targets IDs.', true) + ->param('subject', null, new Nullable(new Text(998)), 'Email Subject.', true) + ->param('content', null, new Nullable(new Text(64230)), 'Email Content.', true) + ->param('draft', null, new Nullable(new Boolean()), 'Is message a draft', true) + ->param('html', null, new Nullable(new Boolean()), 'Is content of type HTML', true) + ->param('cc', null, new Nullable(new ArrayList(new UID())), 'Array of target IDs to be added as CC.', true) + ->param('bcc', null, new Nullable(new ArrayList(new UID())), 'Array of target IDs to be added as BCC.', true) + ->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('attachments', null, new Nullable(new ArrayList(new CompoundUID())), 'Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('dbForPlatform') @@ -4207,12 +4208,12 @@ App::patch('/v1/messaging/messages/sms/:messageId') ) ]) ->param('messageId', '', new UID(), 'Message ID.') - ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) - ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) - ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) - ->param('content', null, new Text(64230), 'Email Content.', true) - ->param('draft', null, new Boolean(), 'Is message a draft', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('topics', null, new Nullable(new ArrayList(new UID())), 'List of Topic IDs.', true) + ->param('users', null, new Nullable(new ArrayList(new UID())), 'List of User IDs.', true) + ->param('targets', null, new Nullable(new ArrayList(new UID())), 'List of Targets IDs.', true) + ->param('content', null, new Nullable(new Text(64230)), 'Email Content.', true) + ->param('draft', null, new Nullable(new Boolean()), 'Is message a draft', true) + ->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('dbForPlatform') @@ -4369,24 +4370,24 @@ App::patch('/v1/messaging/messages/push/:messageId') ] )) ->param('messageId', '', new UID(), 'Message ID.') - ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) - ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) - ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) - ->param('title', null, new Text(256), 'Title for push notification.', true) - ->param('body', null, new Text(64230), 'Body for push notification.', true) - ->param('data', null, new JSON(), 'Additional Data for push notification.', true) - ->param('action', null, new Text(256), 'Action for push notification.', true) - ->param('image', null, new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as :.', true) - ->param('icon', null, new Text(256), 'Icon for push notification. Available only for Android and Web platforms.', true) - ->param('sound', null, new Text(256), 'Sound for push notification. Available only for Android and iOS platforms.', true) - ->param('color', null, new Text(256), 'Color for push notification. Available only for Android platforms.', true) - ->param('tag', null, new Text(256), 'Tag for push notification. Available only for Android platforms.', true) - ->param('badge', null, new Integer(), 'Badge for push notification. Available only for iOS platforms.', true) - ->param('draft', null, new Boolean(), 'Is message a draft', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) - ->param('contentAvailable', null, new Boolean(), 'If set to true, the notification will be delivered in the background. Available only for iOS Platform.', true) - ->param('critical', null, new Boolean(), 'If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.', true) - ->param('priority', null, new WhiteList(['normal', 'high']), 'Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification.', true) + ->param('topics', null, new Nullable(new ArrayList(new UID())), 'List of Topic IDs.', true) + ->param('users', null, new Nullable(new ArrayList(new UID())), 'List of User IDs.', true) + ->param('targets', null, new Nullable(new ArrayList(new UID())), 'List of Targets IDs.', true) + ->param('title', null, new Nullable(new Text(256)), 'Title for push notification.', true) + ->param('body', null, new Nullable(new Text(64230)), 'Body for push notification.', true) + ->param('data', null, new Nullable(new JSON()), 'Additional Data for push notification.', true) + ->param('action', null, new Nullable(new Text(256)), 'Action for push notification.', true) + ->param('image', null, new Nullable(new CompoundUID()), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as :.', true) + ->param('icon', null, new Nullable(new Text(256)), 'Icon for push notification. Available only for Android and Web platforms.', true) + ->param('sound', null, new Nullable(new Text(256)), 'Sound for push notification. Available only for Android and iOS platforms.', true) + ->param('color', null, new Nullable(new Text(256)), 'Color for push notification. Available only for Android platforms.', true) + ->param('tag', null, new Nullable(new Text(256)), 'Tag for push notification. Available only for Android platforms.', true) + ->param('badge', null, new Nullable(new Integer()), 'Badge for push notification. Available only for iOS platforms.', true) + ->param('draft', null, new Nullable(new Boolean()), 'Is message a draft', true) + ->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('contentAvailable', null, new Nullable(new Boolean()), 'If set to true, the notification will be delivered in the background. Available only for iOS Platform.', true) + ->param('critical', null, new Nullable(new Boolean()), 'If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.', true) + ->param('priority', null, new Nullable(new WhiteList(['normal', 'high'])), 'Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('dbForPlatform') diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 390e88637a..a57675d3e8 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -18,6 +18,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DateTimeValidator; use Utopia\Database\Validator\UID; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -526,8 +527,8 @@ App::put('/v1/project/variables/:variableId') )) ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) - ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true) - ->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true) + ->param('value', null, new Nullable(new Text(8192, 0)), 'Variable value. Max length: 8192 chars.', true) + ->param('secret', null, new Nullable(new Boolean()), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true) ->inject('project') ->inject('response') ->inject('dbForProject') diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 2b30b1cd08..760a4f23a6 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -46,6 +46,7 @@ use Utopia\Validator\Boolean; use Utopia\Validator\Hostname; use Utopia\Validator\Integer; use Utopia\Validator\Multiple; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\URL; @@ -678,9 +679,9 @@ App::patch('/v1/projects/:projectId/oauth2') )) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'Provider Name') - ->param('appId', null, new Text(256), 'Provider app ID. Max length: 256 chars.', true) - ->param('secret', null, new text(512), 'Provider secret key. Max length: 512 chars.', true) - ->param('enabled', null, new Boolean(), 'Provider status. Set to \'false\' to disable new session creation.', true) + ->param('appId', null, new Nullable(new Text(256)), 'Provider app ID. Max length: 256 chars.', true) + ->param('secret', null, new Nullable(new text(512)), 'Provider secret key. Max length: 512 chars.', true) + ->param('enabled', null, new Nullable(new Boolean()), 'Provider status. Set to \'false\' to disable new session creation.', true) ->inject('response') ->inject('dbForPlatform') ->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForPlatform) { @@ -1476,8 +1477,8 @@ App::post('/v1/projects/:projectId/keys') )) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') - ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') - ->param('expire', null, new DatetimeValidator(), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true) + ->param('scopes', null, new Nullable(new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE)), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') + ->param('expire', null, new Nullable(new DatetimeValidator()), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForPlatform') ->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForPlatform) { @@ -1615,8 +1616,8 @@ App::put('/v1/projects/:projectId/keys/:keyId') ->param('projectId', '', new UID(), 'Project unique ID.') ->param('keyId', '', new UID(), 'Key unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') - ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') - ->param('expire', null, new DatetimeValidator(), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true) + ->param('scopes', null, new Nullable(new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE)), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') + ->param('expire', null, new Nullable(new DatetimeValidator()), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForPlatform') ->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForPlatform) { diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 72acd7b4a2..22d456c7c6 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -50,6 +50,7 @@ use Utopia\System\System; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -77,7 +78,7 @@ App::post('/v1/storage/buckets') )) ->param('bucketId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Bucket name') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true) ->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan']) @@ -290,7 +291,7 @@ App::put('/v1/storage/buckets/:bucketId') )) ->param('bucketId', '', new UID(), 'Bucket unique ID.') ->param('name', null, new Text(128), 'Bucket name', false) - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true) ->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan']) @@ -418,7 +419,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).') ->param('fileId', '', new CustomId(), 'File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('file', [], new File(), 'Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](https://appwrite.io/docs/products/storage/upload-download#input-file).', skipValidation: true) - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->inject('request') ->inject('response') ->inject('dbForProject') @@ -1645,8 +1646,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') )) ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File unique ID.') - ->param('name', null, new Text(255), 'Name of the file', true) - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('name', null, new Nullable(new Text(255)), 'Name of the file', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->inject('response') ->inject('dbForProject') ->inject('user') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 591a22705d..582a3086a3 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -55,6 +55,7 @@ use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; use Utopia\Validator\Boolean; use Utopia\Validator\Integer; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -208,8 +209,8 @@ App::post('/v1/users') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', null, new Email(), 'User email.', true) - ->param('phone', null, new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('email', null, new Nullable(new Email()), 'User email.', true) + ->param('phone', null, new Nullable(new Phone()), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'Plain text user password. Must be at least 8 chars.', true, ['project', 'passwordsDictionary']) ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php index 6c8e5dcf3d..8dfe80a390 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php @@ -16,6 +16,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends Action { @@ -62,7 +63,7 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Boolean(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new Nullable(new Boolean()), '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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php index d4724ea551..ddb01ff011 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php @@ -64,7 +64,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Boolean()), 'Default value for attribute when not provided. Cannot be set when attribute is required.') - ->param('newKey', null, new Key(), 'New attribute key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php index cb4d0d924b..1a30a09867 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for attribute when not provided. Cannot be set when attribute is required.', injections: ['dbForProject']) - ->param('newKey', null, new Key(), 'New attribute key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php index cbfd66e4d9..9f4c38d490 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php @@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends Action { @@ -63,7 +64,7 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Email(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new Nullable(new Email()), '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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php index 2446722f7a..59a0490e6f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Email()), 'Default value for attribute when not provided. Cannot be set when attribute is required.') - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php index 98ed83861d..d2ccf9f972 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php @@ -18,6 +18,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Create extends Action @@ -66,7 +67,7 @@ class Create extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('elements', [], new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of enum values.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new Nullable(new Text(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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php index 23dc807360..560107dd38 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php @@ -67,7 +67,7 @@ class Update extends Action ->param('elements', null, new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Updated list of enum values.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.') - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php index 83deb92edc..f48348c192 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php @@ -18,6 +18,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; use Utopia\Validator\FloatValidator; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; class Create extends Action @@ -65,9 +66,9 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('min', null, new FloatValidator(), 'Minimum value.', true) - ->param('max', null, new FloatValidator(), 'Maximum value.', true) - ->param('default', null, new FloatValidator(), 'Default value. Cannot be set when required.', true) + ->param('min', null, new Nullable(new FloatValidator()), 'Minimum value.', true) + ->param('max', null, new Nullable(new FloatValidator()), 'Maximum value.', true) + ->param('default', null, new Nullable(new FloatValidator()), 'Default value. Cannot be set when required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php index 7f295a1a94..99ac992b9e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php @@ -64,10 +64,10 @@ class Update extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('min', null, new FloatValidator(), 'Minimum value.', true) - ->param('max', null, new FloatValidator(), 'Maximum value.', true) + ->param('min', null, new Nullable(new FloatValidator()), 'Minimum value.', true) + ->param('max', null, new Nullable(new FloatValidator()), 'Maximum value.', true) ->param('default', null, new Nullable(new FloatValidator()), 'Default value. Cannot be set when required.') - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php index 6e6264466c..af3ed99bdf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php @@ -17,6 +17,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; use Utopia\Validator\IP; +use Utopia\Validator\Nullable; class Create extends Action { @@ -63,7 +64,7 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new IP(), 'Default value. Cannot be set when attribute is required.', true) + ->param('default', null, new Nullable(new IP()), 'Default value. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php index 6cedf10760..a757ed47d1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new IP()), 'Default value. Cannot be set when attribute is required.') - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php index 090d63c403..5e147c771d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php @@ -18,6 +18,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; use Utopia\Validator\Integer; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; class Create extends Action @@ -65,9 +66,9 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('min', null, new Integer(), 'Minimum value', true) - ->param('max', null, new Integer(), 'Maximum value', true) - ->param('default', null, new Integer(), 'Default value. Cannot be set when attribute is required.', true) + ->param('min', null, new Nullable(new Integer()), 'Minimum value', true) + ->param('max', null, new Nullable(new Integer()), 'Maximum value', true) + ->param('default', null, new Nullable(new Integer()), 'Default value. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php index b6ae79bd8a..6d3858992b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php @@ -64,10 +64,10 @@ class Update extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('min', null, new Integer(), 'Minimum value', true) - ->param('max', null, new Integer(), 'Maximum value', true) + ->param('min', null, new Nullable(new Integer()), 'Minimum value', true) + ->param('max', null, new Nullable(new Integer()), 'Maximum value', true) ->param('default', null, new Nullable(new Integer()), 'Default value. Cannot be set when attribute is required.') - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php index 52f04ba5bc..8ef2f96ec2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true) - ->param('newKey', null, new Key(), 'New attribute key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php index 73964ab461..62f35ad2a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true) - ->param('newKey', null, new Key(), 'New attribute key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php index 23eb06f45d..dba83d44d5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Spatial(Database::VAR_POLYGON)), 'Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.', true) - ->param('newKey', null, new Key(), 'New attribute key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php index 75471b826c..6fc27a9836 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php @@ -18,6 +18,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\WhiteList; class Create extends Action @@ -71,8 +72,8 @@ class Create extends Action Database::RELATION_ONE_TO_MANY ], true), 'Relation type') ->param('twoWay', false, new Boolean(), 'Is Two Way?', true) - ->param('key', null, new Key(), 'Attribute Key.', true) - ->param('twoWayKey', null, new Key(), 'Two Way Attribute Key.', true) + ->param('key', null, new Nullable(new Key()), 'Attribute Key.', true) + ->param('twoWayKey', null, new Nullable(new Key()), 'Two Way Attribute Key.', true) ->param('onDelete', Database::RELATION_MUTATE_RESTRICT, new WhiteList([ Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php index 897cbd434f..f9f1d6f3ab 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php @@ -14,6 +14,7 @@ use Utopia\Database\Database; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; use Utopia\Validator\WhiteList; class Update extends Action @@ -61,12 +62,12 @@ class Update extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') - ->param('onDelete', null, new WhiteList([ + ->param('onDelete', null, new Nullable(new WhiteList([ Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL - ], true), 'Constraints option', true) - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ], true)), 'Constraints option', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php index 1527c4d1d9..88cb161505 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php @@ -19,6 +19,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; use Utopia\Validator\Text; @@ -68,7 +69,7 @@ class Create extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Validator::TYPE_INTEGER), 'Attribute size for text attributes, in number of characters.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Text(0, 0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->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') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php index 8614dfb202..6687178cb1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php @@ -67,8 +67,8 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->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.') - ->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Validator::TYPE_INTEGER), 'Maximum size of the string attribute.', true) - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('size', null, new Nullable(new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Validator::TYPE_INTEGER)), 'Maximum size of the string attribute.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php index ce0175966b..2d3b0c6168 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php @@ -16,6 +16,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\URL; class Create extends Action @@ -63,7 +64,7 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new URL(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new Nullable(new URL()), '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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php index 7ba12ad98a..ebaea9e61d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php @@ -65,7 +65,7 @@ class Update extends Action ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new URL()), 'Default value for attribute when not provided. Cannot be set when attribute is required.') - ->param('newKey', null, new Key(), 'New Attribute Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php index b810ce602f..922cc45428 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php @@ -24,6 +24,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Create extends Action @@ -71,7 +72,7 @@ class Create extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(), 'Is collection enabled? When set to \'disabled\', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.', true) ->inject('response') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php index 0b3d0e9fb4..0ff39c4500 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php @@ -25,6 +25,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; use Utopia\Validator\Numeric; class Decrement extends Action @@ -77,8 +78,8 @@ class Decrement extends Action ->param('documentId', '', new UID(), 'Document ID.') ->param('attribute', '', new Key(), 'Attribute key.') ->param('value', 1, new Numeric(), 'Value to increment the attribute by. The value must be a number.', true) - ->param('min', null, new Numeric(), 'Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('min', null, new Nullable(new Numeric()), 'Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php index ef64099fa8..67fe456550 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php @@ -25,6 +25,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; use Utopia\Validator\Numeric; class Increment extends Action @@ -77,8 +78,8 @@ class Increment extends Action ->param('documentId', '', new UID(), 'Document ID.') ->param('attribute', '', new Key(), 'Attribute key.') ->param('value', 1, new Numeric(), 'Value to increment the attribute by. The value must be a number.', true) - ->param('max', null, new Numeric(), 'Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('max', null, new Nullable(new Numeric()), 'Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php index 4b1251e016..76acff63ab 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php @@ -22,6 +22,7 @@ use Utopia\Database\Query; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Delete extends Action @@ -71,7 +72,7 @@ class Delete extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php index 2152534efe..b190ddde19 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php @@ -25,6 +25,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Update extends Action @@ -75,7 +76,7 @@ class Update extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true) ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php index 6c869723a7..5a3712cc26 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php @@ -23,6 +23,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Upsert extends Action { @@ -73,7 +74,7 @@ class Upsert extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID.') ->param('documents', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of document data as JSON objects. May contain partial documents.', false, ['plan']) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index 521190d3dc..09deb5f94d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -29,6 +29,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Create extends Action { @@ -119,9 +120,9 @@ class Create extends Action ->param('documentId', '', new CustomId(), 'Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', true) ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.') ->param('data', [], new JSON(), 'Document data as JSON object.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":30,"isAdmin":false}') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('documents', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of documents data as JSON objects.', true, ['plan']) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('user') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index a4cef59e5f..88f22c2594 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -74,7 +74,7 @@ class Delete extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('documentId', '', new UID(), 'Document ID.') - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('requestTimestamp') ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php index 3d8cd9198c..c92a487697 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php @@ -19,6 +19,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Get extends Action @@ -64,7 +65,7 @@ class Get extends Action ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('documentId', '', new UID(), 'Document ID.') ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID to read uncommitted changes within the transaction.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID to read uncommitted changes within the transaction.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index ed83f3fdd3..6be9a53992 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -27,6 +27,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Update extends Action { @@ -77,8 +78,8 @@ class Update extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('documentId', '', new UID(), 'Document ID.') ->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true) - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('requestTimestamp') ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 8d47410649..a9d8c90a9b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -28,6 +28,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Upsert extends Action { @@ -80,8 +81,8 @@ class Upsert extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->param('documentId', '', new CustomId(), 'Document ID.') ->param('data', [], new JSON(), 'Document data as JSON object. Include all required attributes of the document to be created or updated.') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('requestTimestamp') ->inject('response') ->inject('user') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index f159043531..630170a031 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -23,6 +23,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class XList extends Action @@ -67,7 +68,7 @@ class XList extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID to read uncommitted changes within the transaction.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID to read uncommitted changes within the transaction.', true) ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php index 49870002ce..7575c9803b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php @@ -17,6 +17,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Update extends Action @@ -64,7 +65,7 @@ class Update extends Action ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID.') ->param('name', null, new Text(128), 'Collection name. Max length: 128 chars.') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(), 'Is collection enabled? When set to \'disabled\', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.', true) ->inject('response') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php index 039964b2c6..d9dfc15ca8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php @@ -11,6 +11,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends BooleanCreate { @@ -53,7 +54,7 @@ class Create extends BooleanCreate ->param('tableId', '', new UID(), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, new Boolean(), 'Default value for column when not provided. Cannot be set when column is required.', true) + ->param('default', null, new Nullable(new Boolean()), '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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php index 7df901a1cc..3b83e71c12 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php @@ -57,7 +57,7 @@ class Update extends BooleanUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Boolean()), 'Default value for column when not provided. Cannot be set when column is required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php index 151422af75..255abf00bf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php @@ -59,7 +59,7 @@ class Update extends DatetimeUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for column when not provided. Cannot be set when column is required.', injections: ['dbForProject']) - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php index 3a8d492e4e..58ea459d0f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends EmailCreate { @@ -54,7 +55,7 @@ class Create extends EmailCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, new Email(), 'Default value for column when not provided. Cannot be set when column is required.', true) + ->param('default', null, new Nullable(new Email()), '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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php index 4d32489357..0105345555 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php @@ -58,7 +58,7 @@ class Update extends EmailUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Email()), 'Default value for column when not provided. Cannot be set when column is required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php index 68dc2f8e08..8ab8019626 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php @@ -13,6 +13,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Create extends EnumCreate @@ -57,7 +58,7 @@ class Create extends EnumCreate ->param('key', '', new Key(), 'Column Key.') ->param('elements', [], new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of enum values.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, new Text(0), 'Default value for column when not provided. Cannot be set when column is required.', true) + ->param('default', null, new Nullable(new Text(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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php index 3b611a5fde..968c84c56b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php @@ -61,7 +61,7 @@ class Update extends EnumUpdate ->param('elements', null, new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Updated list of enum values.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Text(0)), 'Default value for column when not provided. Cannot be set when column is required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php index 9fe6987cab..21e855d912 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; use Utopia\Validator\FloatValidator; +use Utopia\Validator\Nullable; class Create extends FloatCreate { @@ -54,9 +55,9 @@ class Create extends FloatCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('min', null, new FloatValidator(), 'Minimum value', true) - ->param('max', null, new FloatValidator(), 'Maximum value', true) - ->param('default', null, new FloatValidator(), 'Default value. Cannot be set when required.', true) + ->param('min', null, new Nullable(new FloatValidator()), 'Minimum value', true) + ->param('max', null, new Nullable(new FloatValidator()), 'Maximum value', true) + ->param('default', null, new Nullable(new FloatValidator()), 'Default value. Cannot be set when required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php index 023e2e834e..6a479ea266 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php @@ -57,10 +57,10 @@ class Update extends FloatUpdate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('min', null, new FloatValidator(), 'Minimum value', true) - ->param('max', null, new FloatValidator(), 'Maximum value', true) + ->param('min', null, new Nullable(new FloatValidator()), 'Minimum value', true) + ->param('max', null, new Nullable(new FloatValidator()), 'Maximum value', true) ->param('default', null, new Nullable(new FloatValidator()), 'Default value. Cannot be set when required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php index 81ca8da81f..08912ebb56 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; use Utopia\Validator\IP; +use Utopia\Validator\Nullable; class Create extends IPCreate { @@ -54,7 +55,7 @@ class Create extends IPCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, new IP(), 'Default value. Cannot be set when column is required.', true) + ->param('default', null, new Nullable(new IP()), 'Default value. Cannot be set when column is required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php index 0db95b0206..9df9f573a2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php @@ -58,7 +58,7 @@ class Update extends IPUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new IP()), 'Default value. Cannot be set when column is required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php index dfca51a6c5..eb9230f48f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; use Utopia\Validator\Integer; +use Utopia\Validator\Nullable; class Create extends IntegerCreate { @@ -54,9 +55,9 @@ class Create extends IntegerCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('min', null, new Integer(), 'Minimum value', true) - ->param('max', null, new Integer(), 'Maximum value', true) - ->param('default', null, new Integer(), 'Default value. Cannot be set when column is required.', true) + ->param('min', null, new Nullable(new Integer()), 'Minimum value', true) + ->param('max', null, new Nullable(new Integer()), 'Maximum value', true) + ->param('default', null, new Nullable(new Integer()), 'Default value. Cannot be set when column is required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php index a1568d069b..6c707f1655 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php @@ -57,10 +57,10 @@ class Update extends IntegerUpdate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('min', null, new Integer(), 'Minimum value', true) - ->param('max', null, new Integer(), 'Maximum value', true) + ->param('min', null, new Nullable(new Integer()), 'Minimum value', true) + ->param('max', null, new Nullable(new Integer()), 'Maximum value', true) ->param('default', null, new Nullable(new Integer()), 'Default value. Cannot be set when column is required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php index d3823445a2..fd7d200eb3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php @@ -59,7 +59,7 @@ class Update extends LineUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.', true) - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php index 3c855e137c..8b8dd7b66c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php @@ -59,7 +59,7 @@ class Update extends PointUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.', true) - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php index 866bbaf8b0..c49351fc59 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php @@ -59,7 +59,7 @@ class Update extends PolygonUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Spatial(Database::VAR_POLYGON)), 'Default value for column when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when column is required.', true) - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php index 0a6c76d8c5..cccc61beaa 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\WhiteList; class Create extends RelationshipCreate @@ -61,8 +62,8 @@ class Create extends RelationshipCreate Database::RELATION_ONE_TO_MANY ], true), 'Relation type') ->param('twoWay', false, new Boolean(), 'Is Two Way?', true) - ->param('key', null, new Key(), 'Column Key.', true) - ->param('twoWayKey', null, new Key(), 'Two Way Column Key.', true) + ->param('key', null, new Nullable(new Key()), 'Column Key.', true) + ->param('twoWayKey', null, new Nullable(new Key()), 'Two Way Column Key.', true) ->param('onDelete', Database::RELATION_MUTATE_RESTRICT, new WhiteList([ Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php index b645454be1..5953d600f8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php @@ -12,6 +12,7 @@ use Utopia\Database\Database; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; use Utopia\Validator\WhiteList; class Update extends RelationshipUpdate @@ -55,12 +56,12 @@ class Update extends RelationshipUpdate ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') - ->param('onDelete', null, new WhiteList([ + ->param('onDelete', null, new Nullable(new WhiteList([ Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL - ], true), 'Constraints option', true) - ->param('newKey', null, new Key(), 'New Column Key.', true) + ], true)), 'Constraints option', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php index 6fe9fd679c..8d37c9011b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Range; use Utopia\Validator\Text; @@ -57,7 +58,7 @@ class Create extends StringCreate ->param('key', '', new Key(), 'Column Key.') ->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Validator::TYPE_INTEGER), 'Column size for text columns, in number of characters.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, new Text(0, 0), 'Default value for column when not provided. Cannot be set when column is required.', true) + ->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') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php index 5ec9b78dda..43083616ba 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php @@ -60,8 +60,8 @@ class Update extends StringUpdate ->param('key', '', new Key(), 'Column Key.') ->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.') - ->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Validator::TYPE_INTEGER), 'Maximum size of the string column.', true) - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('size', null, new Nullable(new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Validator::TYPE_INTEGER)), 'Maximum size of the string column.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php index 99ec36b721..3fd6f1e463 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php @@ -11,6 +11,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\URL; class Create extends URLCreate @@ -54,7 +55,7 @@ class Create extends URLCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, new URL(), 'Default value for column when not provided. Cannot be set when column is required.', true) + ->param('default', null, new Nullable(new URL()), '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) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php index 51168b0383..64dfdfbf69 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php @@ -58,7 +58,7 @@ class Update extends URLUpdate ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new URL()), 'Default value for column when not provided. Cannot be set when column is required.') - ->param('newKey', null, new Key(), 'New Column Key.', true) + ->param('newKey', null, new Nullable(new Key()), 'New Column Key.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php index 4f62200d7c..68d3e772ec 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php @@ -13,6 +13,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Create extends CollectionCreate @@ -56,7 +57,7 @@ class Create extends CollectionCreate ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Table name. Max length: 128 chars.') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('rowSecurity', false, new Boolean(true), 'Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(), 'Is table enabled? When set to \'disabled\', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.', true) ->inject('response') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php index 86e9a48f63..accb0392fe 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php @@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Delete extends DocumentsDelete @@ -56,7 +57,7 @@ class Delete extends DocumentsDelete ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new UID(), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).') ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php index 5005ab4f41..856f17ed10 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Update extends DocumentsUpdate @@ -58,7 +59,7 @@ class Update extends DocumentsUpdate ->param('tableId', '', new UID(), 'Table ID.') ->param('data', [], new JSON(), 'Row data as JSON object. Include only column and value pairs to be updated.', true) ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php index d0a1f08003..492af25e9f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Upsert extends DocumentsUpsert { @@ -58,7 +59,7 @@ class Upsert extends DocumentsUpsert ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new UID(), 'Table ID.') ->param('rows', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of row data as JSON objects. May contain partial rows.', false, ['plan']) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php index d42cf5e9eb..42f2919ce1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php @@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; use Utopia\Validator\Numeric; class Decrement extends DecrementDocumentAttribute @@ -59,8 +60,8 @@ class Decrement extends DecrementDocumentAttribute ->param('rowId', '', new UID(), 'Row ID.') ->param('column', '', new Key(), 'Column key.') ->param('value', 1, new Numeric(), 'Value to increment the column by. The value must be a number.', true) - ->param('min', null, new Numeric(), 'Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('min', null, new Nullable(new Numeric()), 'Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php index c58e16c8e3..3d04d71c26 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php @@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; use Utopia\Validator\Numeric; class Increment extends IncrementDocumentAttribute @@ -59,8 +60,8 @@ class Increment extends IncrementDocumentAttribute ->param('rowId', '', new UID(), 'Row ID.') ->param('column', '', new Key(), 'Column key.') ->param('value', 1, new Numeric(), 'Value to increment the column by. The value must be a number.', true) - ->param('max', null, new Numeric(), 'Maximum value for the column. If the current value is greater than this value, an error will be thrown.', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('max', null, new Nullable(new Numeric()), 'Maximum value for the column. If the current value is greater than this value, an error will be thrown.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php index bfc832f2b5..d657e5596b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php @@ -16,6 +16,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Create extends DocumentCreate { @@ -98,9 +99,9 @@ class Create extends DocumentCreate ->param('rowId', '', new CustomId(), 'Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', true) ->param('tableId', '', new UID(), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows.') ->param('data', [], new JSON(), 'Row data as JSON object.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":30,"isAdmin":false}') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('rows', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of rows data as JSON objects.', true, ['plan']) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('response') ->inject('dbForProject') ->inject('user') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php index 687b1c8c11..d18a81c1af 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php @@ -61,7 +61,7 @@ class Delete extends DocumentDelete ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new UID(), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).') ->param('rowId', '', new UID(), 'Row ID.') - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('requestTimestamp') ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php index f8b70516b6..f355ebb9e6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php @@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Get extends DocumentGet @@ -52,7 +53,7 @@ class Get extends DocumentGet ->param('tableId', '', new UID(), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).') ->param('rowId', '', new UID(), 'Row ID.') ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID to read uncommitted changes within the transaction.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID to read uncommitted changes within the transaction.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php index cb1d5888cf..8f3786b8cf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php @@ -13,6 +13,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Update extends DocumentUpdate { @@ -59,8 +60,8 @@ class Update extends DocumentUpdate ->param('tableId', '', new UID(), 'Table ID.') ->param('rowId', '', new UID(), 'Row ID.') ->param('data', [], new JSON(), 'Row data as JSON object. Include only columns and value pairs to be updated.', true) - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('requestTimestamp') ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php index 0bc373cc93..d4cd61cfdd 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php @@ -13,6 +13,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\JSON; +use Utopia\Validator\Nullable; class Upsert extends DocumentUpsert { @@ -61,8 +62,8 @@ class Upsert extends DocumentUpsert ->param('tableId', '', new UID(), 'Table ID.') ->param('rowId', '', new UID(), 'Row ID.') ->param('data', [], new JSON(), 'Row data as JSON object. Include all required columns of the row to be created or updated.', true) - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) ->inject('requestTimestamp') ->inject('response') ->inject('user') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php index b96e84b722..cd6141a6b4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class XList extends DocumentXList @@ -52,7 +53,7 @@ class XList extends DocumentXList ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new UID(), 'Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/products/databases/tables#create-table).') ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) - ->param('transactionId', null, new UID(), 'Transaction ID to read uncommitted changes within the transaction.', true) + ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID to read uncommitted changes within the transaction.', true) ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php index 8424b37a6d..a6cb611870 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php @@ -12,6 +12,7 @@ use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Update extends CollectionUpdate @@ -55,7 +56,7 @@ class Update extends CollectionUpdate ->param('databaseId', '', new UID(), 'Database ID.') ->param('tableId', '', new UID(), 'Table ID.') ->param('name', null, new Text(128), 'Table name. Max length: 128 chars.') - ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('rowSecurity', false, new Boolean(true), 'Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(), 'Is table enabled? When set to \'disabled\', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.', true) ->inject('response') diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php index f64a960507..d53324b27f 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php @@ -28,6 +28,7 @@ use Utopia\Storage\Validator\Upload; use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Create extends Action @@ -74,8 +75,8 @@ class Create extends Action packaging: true, )) ->param('functionId', '', new UID(), 'Function ID.') - ->param('entrypoint', null, new Text(1028), 'Entrypoint File.', true) - ->param('commands', null, new Text(8192, 0), 'Build Commands.', true) + ->param('entrypoint', null, new Nullable(new Text(1028)), 'Entrypoint File.', true) + ->param('commands', null, new Nullable(new Text(8192, 0)), 'Build Commands.', true) ->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true) ->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.') ->inject('request') diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index 69af3b7d04..a699c0f097 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -36,6 +36,7 @@ use Utopia\System\System; use Utopia\Validator\AnyOf; use Utopia\Validator\Assoc; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -81,7 +82,7 @@ class Create extends Base ->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true) ->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'], true), 'HTTP method of execution. Default value is POST.', true) ->param('headers', [], new AnyOf([new Assoc(), new Text(65535)], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true) - ->param('scheduledAt', null, new Text(100), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true) + ->param('scheduledAt', null, new Nullable(new Text(100)), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true) ->inject('response') ->inject('request') ->inject('project') diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php index 639b1c74d5..95fd235e4b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php @@ -16,6 +16,7 @@ use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Update extends Base @@ -56,8 +57,8 @@ class Update extends Base ->param('functionId', '', new UID(), 'Function unique ID.', false) ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) - ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true) - ->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only functions can read them during build and runtime.', true) + ->param('value', null, new Nullable(new Text(8192, 0)), 'Variable value. Max length: 8192 chars.', true) + ->param('secret', null, new Nullable(new Boolean()), 'Secret variables can be updated or deleted, but only functions can read them during build and runtime.', true) ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index 4bd3afa1f5..aa622d8d84 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -29,6 +29,7 @@ use Utopia\Storage\Validator\Upload; use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Create extends Action @@ -71,9 +72,9 @@ class Create extends Action packaging: true, )) ->param('siteId', '', new UID(), 'Site ID.') - ->param('installCommand', null, new Text(8192, 0), 'Install Commands.', true) - ->param('buildCommand', null, new Text(8192, 0), 'Build Commands.', true) - ->param('outputDirectory', null, new Text(8192, 0), 'Output Directory.', true) + ->param('installCommand', null, new Nullable(new Text(8192, 0)), 'Install Commands.', true) + ->param('buildCommand', null, new Nullable(new Text(8192, 0)), 'Build Commands.', true) + ->param('outputDirectory', null, new Nullable(new Text(8192, 0)), 'Output Directory.', true) ->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true) ->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.') ->inject('request') diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php index 3cf2e2f85f..6f4ea35eea 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/Update.php @@ -14,6 +14,7 @@ use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; use Utopia\Validator\Text; class Update extends Base @@ -54,8 +55,8 @@ class Update extends Base ->param('siteId', '', new UID(), 'Site unique ID.', false) ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) - ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true) - ->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only sites can read them during build and runtime.', true) + ->param('value', null, new Nullable(new Text(8192, 0)), 'Variable value. Max length: 8192 chars.', true) + ->param('secret', null, new Nullable(new Boolean()), 'Secret variables can be updated or deleted, but only sites can read them during build and runtime.', true) ->inject('response') ->inject('dbForProject') ->callback($this->action(...)); From 0ed4b5dbe70dcdb3bb1ddd45a16e7f976fc90272 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 10 Nov 2025 10:16:58 +0530 Subject: [PATCH 089/167] fix imports + add spec changes --- app/config/specs/open-api3-1.8.x-client.json | 78 ++- app/config/specs/open-api3-1.8.x-console.json | 582 ++++++++++++------ app/config/specs/open-api3-1.8.x-server.json | 555 +++++++++++------ app/config/specs/open-api3-latest-client.json | 78 ++- .../specs/open-api3-latest-console.json | 582 ++++++++++++------ app/config/specs/open-api3-latest-server.json | 555 +++++++++++------ app/config/specs/swagger2-1.8.x-client.json | 61 +- app/config/specs/swagger2-1.8.x-console.json | 508 ++++++++++----- app/config/specs/swagger2-1.8.x-server.json | 485 ++++++++++----- app/config/specs/swagger2-latest-client.json | 61 +- app/config/specs/swagger2-latest-console.json | 508 ++++++++++----- app/config/specs/swagger2-latest-server.json | 485 ++++++++++----- .../Collections/Documents/Delete.php | 1 + .../Http/TablesDB/Tables/Rows/Delete.php | 1 + 14 files changed, 3068 insertions(+), 1472 deletions(-) diff --git a/app/config/specs/open-api3-1.8.x-client.json b/app/config/specs/open-api3-1.8.x-client.json index dde8390820..9adb21d960 100644 --- a/app/config/specs/open-api3-1.8.x-client.json +++ b/app/config/specs/open-api3-1.8.x-client.json @@ -6313,7 +6313,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documents": { "type": "array", @@ -6326,7 +6327,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -6583,12 +6585,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } }, "required": [ @@ -6701,12 +6705,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -6801,7 +6807,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -6920,12 +6927,14 @@ "min": { "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -7044,12 +7053,14 @@ "max": { "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -7251,7 +7262,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -8194,7 +8206,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } }, "required": [ @@ -8360,7 +8373,8 @@ "name": { "type": "string", "description": "Name of the file", - "x-example": "" + "x-example": "", + "x-nullable": true }, "permissions": { "type": "array", @@ -8368,7 +8382,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -9500,7 +9515,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rows": { "type": "array", @@ -9513,7 +9529,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -9763,12 +9780,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -9877,12 +9896,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -9976,7 +9997,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -10094,12 +10116,14 @@ "min": { "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -10217,12 +10241,14 @@ "max": { "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } 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 aa1e81dbeb..d7c156cdcd 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -7059,7 +7059,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -7245,7 +7246,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -7524,7 +7526,8 @@ "default": { "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7644,7 +7647,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7869,7 +7873,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7974,7 +7979,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -8094,7 +8100,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8207,7 +8214,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "array": { "type": "boolean", @@ -8336,7 +8344,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8442,17 +8451,20 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8566,12 +8578,14 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8582,7 +8596,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8687,17 +8702,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8811,12 +8829,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8827,7 +8847,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8932,7 +8953,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -9052,7 +9074,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9287,7 +9310,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9521,7 +9545,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9755,7 +9780,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9872,12 +9898,14 @@ "key": { "type": "string", "description": "Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -9999,7 +10027,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "array": { "type": "boolean", @@ -10125,12 +10154,14 @@ "size": { "type": "integer", "description": "Maximum size of the string attribute.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10235,7 +10266,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -10355,7 +10387,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10656,12 +10689,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10945,7 +10980,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documents": { "type": "array", @@ -10958,7 +10994,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -11089,7 +11126,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } }, "required": [ @@ -11195,7 +11233,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -11293,7 +11332,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -11550,12 +11590,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } }, "required": [ @@ -11668,12 +11710,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -11768,7 +11812,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -11984,12 +12029,14 @@ "min": { "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -12108,12 +12155,14 @@ "max": { "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -14166,12 +14215,14 @@ "entrypoint": { "type": "string", "description": "Entrypoint File.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "commands": { "type": "string", "description": "Build Commands.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "code": { "type": "string", @@ -14959,7 +15010,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", - "x-example": "" + "x-example": "", + "x-nullable": true } } } @@ -15488,12 +15540,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17599,7 +17653,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17685,7 +17740,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -17693,7 +17749,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -17701,27 +17758,32 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "subject": { "type": "string", "description": "Email Subject.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "" + "x-example": "", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", @@ -17729,7 +17791,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "bcc": { "type": "array", @@ -17737,12 +17800,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", @@ -17750,7 +17815,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -17855,7 +17921,8 @@ "data": { "type": "object", "description": "Additional key-value pair data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -17900,7 +17967,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -18005,7 +18073,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -18013,7 +18082,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -18021,77 +18091,92 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "title": { "type": "string", "description": "Title for push notification.", - "x-example": "" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -18102,7 +18187,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -18275,7 +18361,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -18426,7 +18513,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -18434,7 +18522,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -18442,22 +18531,26 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -19002,7 +19095,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19157,7 +19251,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -19182,7 +19277,8 @@ "sandbox": { "type": "boolean", "description": "Use APNS sandbox environment.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19320,12 +19416,14 @@ "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19472,12 +19570,14 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -19563,7 +19663,8 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19588,7 +19689,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19685,12 +19787,14 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19801,7 +19905,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19888,7 +19993,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -20004,7 +20110,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20091,7 +20198,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20217,7 +20325,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20304,7 +20413,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20551,7 +20661,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20724,7 +20835,8 @@ "port": { "type": "integer", "description": "SMTP port.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -20751,7 +20863,8 @@ "autoTLS": { "type": "boolean", "description": "Enable SMTP AutoTLS feature.", - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -20781,7 +20894,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -20872,7 +20986,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20959,7 +21074,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -21065,7 +21181,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21152,7 +21269,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -21258,7 +21376,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21345,7 +21464,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -21451,7 +21571,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21538,7 +21659,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -22146,7 +22268,8 @@ "name": { "type": "string", "description": "Topic Name.", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", @@ -22154,7 +22277,8 @@ "x-example": "[\"any\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -24227,12 +24351,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only projects can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -26552,12 +26678,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "expire": { "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26723,12 +26851,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "expire": { "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26918,17 +27048,20 @@ "appId": { "type": "string", "description": "Provider app ID. Max length: 256 chars.", - "x-example": "<APP_ID>" + "x-example": "<APP_ID>", + "x-nullable": true }, "secret": { "type": "string", "description": "Provider secret key. Max length: 512 chars.", - "x-example": "<SECRET>" + "x-example": "<SECRET>", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Provider status. Set to 'false' to disable new session creation.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -31983,17 +32116,20 @@ "installCommand": { "type": "string", "description": "Install Commands.", - "x-example": "<INSTALL_COMMAND>" + "x-example": "<INSTALL_COMMAND>", + "x-nullable": true }, "buildCommand": { "type": "string", "description": "Build Commands.", - "x-example": "<BUILD_COMMAND>" + "x-example": "<BUILD_COMMAND>", + "x-nullable": true }, "outputDirectory": { "type": "string", "description": "Output Directory.", - "x-example": "<OUTPUT_DIRECTORY>" + "x-example": "<OUTPUT_DIRECTORY>", + "x-nullable": true }, "code": { "type": "string", @@ -33186,12 +33322,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -33418,7 +33556,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -33611,7 +33750,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -33902,7 +34042,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } }, "required": [ @@ -34068,7 +34209,8 @@ "name": { "type": "string", "description": "Name of the file", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", @@ -34076,7 +34218,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -35761,7 +35904,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -35945,7 +36089,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -36221,7 +36366,8 @@ "default": { "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -36340,7 +36486,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36563,7 +36710,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36667,7 +36815,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -36786,7 +36935,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36898,7 +37048,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -37026,7 +37177,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37131,17 +37283,20 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37254,12 +37409,14 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -37270,7 +37427,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37374,17 +37532,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37497,12 +37658,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -37513,7 +37676,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37617,7 +37781,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37736,7 +37901,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37969,7 +38135,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38201,7 +38368,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38433,7 +38601,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38549,12 +38718,14 @@ "key": { "type": "string", "description": "Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -38675,7 +38846,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -38800,12 +38972,14 @@ "size": { "type": "integer", "description": "Maximum size of the string column.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38909,7 +39083,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -39028,7 +39203,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -39326,12 +39502,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -40076,7 +40254,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rows": { "type": "array", @@ -40089,7 +40268,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40215,7 +40395,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -40320,7 +40501,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40417,7 +40599,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40667,12 +40850,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40781,12 +40966,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40880,7 +41067,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -41094,12 +41282,14 @@ "min": { "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -41217,12 +41407,14 @@ "max": { "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -43091,12 +43283,14 @@ "email": { "type": "string", "description": "User email.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", 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 c3df6ef373..64e119e68a 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -6521,7 +6521,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -6709,7 +6710,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -6991,7 +6993,8 @@ "default": { "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7112,7 +7115,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7339,7 +7343,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7445,7 +7450,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -7566,7 +7572,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7680,7 +7687,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -7810,7 +7818,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7917,17 +7926,20 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8042,12 +8054,14 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8058,7 +8072,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8164,17 +8179,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8289,12 +8307,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8305,7 +8325,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8411,7 +8432,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8532,7 +8554,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8769,7 +8792,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9005,7 +9029,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9241,7 +9266,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9359,12 +9385,14 @@ "key": { "type": "string", "description": "Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -9487,7 +9515,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -9614,12 +9643,14 @@ "size": { "type": "integer", "description": "Maximum size of the string attribute.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9725,7 +9756,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -9846,7 +9878,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10150,12 +10183,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10445,7 +10480,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documents": { "type": "array", @@ -10458,7 +10494,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10591,7 +10628,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -10698,7 +10736,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10797,7 +10836,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11059,12 +11099,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11179,12 +11221,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11281,7 +11325,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11402,12 +11447,14 @@ "min": { "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11528,12 +11575,14 @@ "max": { "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -12953,12 +13002,14 @@ "entrypoint": { "type": "string", "description": "Entrypoint File.", - "x-example": "<ENTRYPOINT>" + "x-example": "<ENTRYPOINT>", + "x-nullable": true }, "commands": { "type": "string", "description": "Build Commands.", - "x-example": "<COMMANDS>" + "x-example": "<COMMANDS>", + "x-nullable": true }, "code": { "type": "string", @@ -13757,7 +13808,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -14211,12 +14263,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -16367,7 +16421,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -16454,7 +16509,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -16462,7 +16518,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -16470,27 +16527,32 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "subject": { "type": "string", "description": "Email Subject.", - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", @@ -16498,7 +16560,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "bcc": { "type": "array", @@ -16506,12 +16569,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", @@ -16519,7 +16584,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -16625,7 +16691,8 @@ "data": { "type": "object", "description": "Additional key-value pair data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -16670,7 +16737,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -16776,7 +16844,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -16784,7 +16853,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -16792,77 +16862,92 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "title": { "type": "string", "description": "Title for push notification.", - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -16873,7 +16958,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -17049,7 +17135,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17203,7 +17290,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -17211,7 +17299,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -17219,22 +17308,26 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -17787,7 +17880,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17945,7 +18039,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -17970,7 +18065,8 @@ "sandbox": { "type": "boolean", "description": "Use APNS sandbox environment.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -18111,12 +18207,14 @@ "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18266,12 +18364,14 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -18358,7 +18458,8 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18383,7 +18484,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18481,12 +18583,14 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18598,7 +18702,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18686,7 +18791,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -18803,7 +18909,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18891,7 +18998,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19018,7 +19126,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19106,7 +19215,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19356,7 +19466,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19532,7 +19643,8 @@ "port": { "type": "integer", "description": "SMTP port.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -19559,7 +19671,8 @@ "autoTLS": { "type": "boolean", "description": "Enable SMTP AutoTLS feature.", - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -19589,7 +19702,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19681,7 +19795,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19769,7 +19884,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -19876,7 +19992,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19964,7 +20081,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -20071,7 +20189,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20159,7 +20278,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -20266,7 +20386,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20354,7 +20475,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20970,7 +21092,8 @@ "name": { "type": "string", "description": "Topic Name.", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", @@ -20978,7 +21101,8 @@ "x-example": "[\"any\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -22508,17 +22632,20 @@ "installCommand": { "type": "string", "description": "Install Commands.", - "x-example": "<INSTALL_COMMAND>" + "x-example": "<INSTALL_COMMAND>", + "x-nullable": true }, "buildCommand": { "type": "string", "description": "Build Commands.", - "x-example": "<BUILD_COMMAND>" + "x-example": "<BUILD_COMMAND>", + "x-nullable": true }, "outputDirectory": { "type": "string", "description": "Output Directory.", - "x-example": "<OUTPUT_DIRECTORY>" + "x-example": "<OUTPUT_DIRECTORY>", + "x-nullable": true }, "code": { "type": "string", @@ -23643,12 +23770,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -23878,7 +24007,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -24073,7 +24203,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -24369,7 +24500,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } }, "required": [ @@ -24539,7 +24671,8 @@ "name": { "type": "string", "description": "Name of the file", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", @@ -24547,7 +24680,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -26008,7 +26142,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -26194,7 +26329,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -26473,7 +26609,8 @@ "default": { "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -26593,7 +26730,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26818,7 +26956,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26923,7 +27062,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -27043,7 +27183,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27156,7 +27297,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -27285,7 +27427,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27391,17 +27534,20 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27515,12 +27661,14 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -27531,7 +27679,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27636,17 +27785,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27760,12 +27912,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -27776,7 +27930,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27881,7 +28036,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -28001,7 +28157,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28236,7 +28393,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28470,7 +28628,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28704,7 +28863,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28821,12 +28981,14 @@ "key": { "type": "string", "description": "Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -28948,7 +29110,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -29074,12 +29237,14 @@ "size": { "type": "integer", "description": "Maximum size of the string column.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29184,7 +29349,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -29304,7 +29470,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29605,12 +29772,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -30279,7 +30448,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rows": { "type": "array", @@ -30292,7 +30462,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30420,7 +30591,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -30526,7 +30698,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30624,7 +30797,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30879,12 +31053,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30995,12 +31171,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31096,7 +31274,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31216,12 +31395,14 @@ "min": { "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31341,12 +31522,14 @@ "max": { "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -32959,12 +33142,14 @@ "email": { "type": "string", "description": "User email.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index dde8390820..9adb21d960 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -6313,7 +6313,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documents": { "type": "array", @@ -6326,7 +6327,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6583,12 +6585,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -6701,12 +6705,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6801,7 +6807,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6920,12 +6927,14 @@ "min": { "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -7044,12 +7053,14 @@ "max": { "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -7251,7 +7262,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -8194,7 +8206,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } }, "required": [ @@ -8360,7 +8373,8 @@ "name": { "type": "string", "description": "Name of the file", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", @@ -8368,7 +8382,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -9500,7 +9515,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rows": { "type": "array", @@ -9513,7 +9529,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9763,12 +9780,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9877,12 +9896,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9976,7 +9997,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10094,12 +10116,14 @@ "min": { "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10217,12 +10241,14 @@ "max": { "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index aa1e81dbeb..d7c156cdcd 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -7059,7 +7059,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -7245,7 +7246,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -7524,7 +7526,8 @@ "default": { "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7644,7 +7647,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7869,7 +7873,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7974,7 +7979,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -8094,7 +8100,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8207,7 +8214,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -8336,7 +8344,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8442,17 +8451,20 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8566,12 +8578,14 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8582,7 +8596,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8687,17 +8702,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8811,12 +8829,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8827,7 +8847,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8932,7 +8953,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -9052,7 +9074,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9287,7 +9310,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9521,7 +9545,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9755,7 +9780,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9872,12 +9898,14 @@ "key": { "type": "string", "description": "Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -9999,7 +10027,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -10125,12 +10154,14 @@ "size": { "type": "integer", "description": "Maximum size of the string attribute.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10235,7 +10266,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -10355,7 +10387,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10656,12 +10689,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10945,7 +10980,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documents": { "type": "array", @@ -10958,7 +10994,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11089,7 +11126,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11195,7 +11233,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11293,7 +11332,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11550,12 +11590,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11668,12 +11710,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11768,7 +11812,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11984,12 +12029,14 @@ "min": { "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -12108,12 +12155,14 @@ "max": { "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -14166,12 +14215,14 @@ "entrypoint": { "type": "string", "description": "Entrypoint File.", - "x-example": "<ENTRYPOINT>" + "x-example": "<ENTRYPOINT>", + "x-nullable": true }, "commands": { "type": "string", "description": "Build Commands.", - "x-example": "<COMMANDS>" + "x-example": "<COMMANDS>", + "x-nullable": true }, "code": { "type": "string", @@ -14959,7 +15010,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -15488,12 +15540,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17599,7 +17653,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17685,7 +17740,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -17693,7 +17749,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -17701,27 +17758,32 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "subject": { "type": "string", "description": "Email Subject.", - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", @@ -17729,7 +17791,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "bcc": { "type": "array", @@ -17737,12 +17800,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", @@ -17750,7 +17815,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -17855,7 +17921,8 @@ "data": { "type": "object", "description": "Additional key-value pair data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -17900,7 +17967,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -18005,7 +18073,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -18013,7 +18082,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -18021,77 +18091,92 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "title": { "type": "string", "description": "Title for push notification.", - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -18102,7 +18187,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -18275,7 +18361,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -18426,7 +18513,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -18434,7 +18522,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -18442,22 +18531,26 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -19002,7 +19095,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19157,7 +19251,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -19182,7 +19277,8 @@ "sandbox": { "type": "boolean", "description": "Use APNS sandbox environment.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19320,12 +19416,14 @@ "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19472,12 +19570,14 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -19563,7 +19663,8 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19588,7 +19689,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19685,12 +19787,14 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19801,7 +19905,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19888,7 +19993,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -20004,7 +20110,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20091,7 +20198,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20217,7 +20325,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20304,7 +20413,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20551,7 +20661,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20724,7 +20835,8 @@ "port": { "type": "integer", "description": "SMTP port.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -20751,7 +20863,8 @@ "autoTLS": { "type": "boolean", "description": "Enable SMTP AutoTLS feature.", - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -20781,7 +20894,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -20872,7 +20986,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20959,7 +21074,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -21065,7 +21181,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21152,7 +21269,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -21258,7 +21376,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21345,7 +21464,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -21451,7 +21571,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21538,7 +21659,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -22146,7 +22268,8 @@ "name": { "type": "string", "description": "Topic Name.", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", @@ -22154,7 +22277,8 @@ "x-example": "[\"any\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -24227,12 +24351,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only projects can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -26552,12 +26678,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "expire": { "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26723,12 +26851,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "expire": { "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26918,17 +27048,20 @@ "appId": { "type": "string", "description": "Provider app ID. Max length: 256 chars.", - "x-example": "<APP_ID>" + "x-example": "<APP_ID>", + "x-nullable": true }, "secret": { "type": "string", "description": "Provider secret key. Max length: 512 chars.", - "x-example": "<SECRET>" + "x-example": "<SECRET>", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Provider status. Set to 'false' to disable new session creation.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -31983,17 +32116,20 @@ "installCommand": { "type": "string", "description": "Install Commands.", - "x-example": "<INSTALL_COMMAND>" + "x-example": "<INSTALL_COMMAND>", + "x-nullable": true }, "buildCommand": { "type": "string", "description": "Build Commands.", - "x-example": "<BUILD_COMMAND>" + "x-example": "<BUILD_COMMAND>", + "x-nullable": true }, "outputDirectory": { "type": "string", "description": "Output Directory.", - "x-example": "<OUTPUT_DIRECTORY>" + "x-example": "<OUTPUT_DIRECTORY>", + "x-nullable": true }, "code": { "type": "string", @@ -33186,12 +33322,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -33418,7 +33556,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -33611,7 +33750,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -33902,7 +34042,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } }, "required": [ @@ -34068,7 +34209,8 @@ "name": { "type": "string", "description": "Name of the file", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", @@ -34076,7 +34218,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -35761,7 +35904,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -35945,7 +36089,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -36221,7 +36366,8 @@ "default": { "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -36340,7 +36486,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36563,7 +36710,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36667,7 +36815,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -36786,7 +36935,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36898,7 +37048,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -37026,7 +37177,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37131,17 +37283,20 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37254,12 +37409,14 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -37270,7 +37427,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37374,17 +37532,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37497,12 +37658,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -37513,7 +37676,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37617,7 +37781,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37736,7 +37901,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37969,7 +38135,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38201,7 +38368,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38433,7 +38601,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38549,12 +38718,14 @@ "key": { "type": "string", "description": "Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -38675,7 +38846,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -38800,12 +38972,14 @@ "size": { "type": "integer", "description": "Maximum size of the string column.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38909,7 +39083,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -39028,7 +39203,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -39326,12 +39502,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -40076,7 +40254,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rows": { "type": "array", @@ -40089,7 +40268,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40215,7 +40395,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -40320,7 +40501,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40417,7 +40599,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40667,12 +40850,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40781,12 +40966,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40880,7 +41067,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -41094,12 +41282,14 @@ "min": { "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -41217,12 +41407,14 @@ "max": { "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -43091,12 +43283,14 @@ "email": { "type": "string", "description": "User email.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index c3df6ef373..64e119e68a 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -6521,7 +6521,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -6709,7 +6710,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documentSecurity": { "type": "boolean", @@ -6991,7 +6993,8 @@ "default": { "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7112,7 +7115,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7339,7 +7343,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7445,7 +7450,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -7566,7 +7572,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7680,7 +7687,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -7810,7 +7818,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7917,17 +7926,20 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8042,12 +8054,14 @@ "min": { "type": "number", "description": "Minimum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8058,7 +8072,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8164,17 +8179,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8289,12 +8307,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8305,7 +8325,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8411,7 +8432,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8532,7 +8554,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8769,7 +8792,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9005,7 +9029,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9241,7 +9266,8 @@ "newKey": { "type": "string", "description": "New attribute key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9359,12 +9385,14 @@ "key": { "type": "string", "description": "Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -9487,7 +9515,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -9614,12 +9643,14 @@ "size": { "type": "integer", "description": "Maximum size of the string attribute.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9725,7 +9756,8 @@ "default": { "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -9846,7 +9878,8 @@ "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10150,12 +10183,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10445,7 +10480,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "documents": { "type": "array", @@ -10458,7 +10494,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10591,7 +10628,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -10698,7 +10736,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10797,7 +10836,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11059,12 +11099,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11179,12 +11221,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11281,7 +11325,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11402,12 +11447,14 @@ "min": { "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11528,12 +11575,14 @@ "max": { "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -12953,12 +13002,14 @@ "entrypoint": { "type": "string", "description": "Entrypoint File.", - "x-example": "<ENTRYPOINT>" + "x-example": "<ENTRYPOINT>", + "x-nullable": true }, "commands": { "type": "string", "description": "Build Commands.", - "x-example": "<COMMANDS>" + "x-example": "<COMMANDS>", + "x-nullable": true }, "code": { "type": "string", @@ -13757,7 +13808,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -14211,12 +14263,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -16367,7 +16421,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -16454,7 +16509,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -16462,7 +16518,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -16470,27 +16527,32 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "subject": { "type": "string", "description": "Email Subject.", - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", @@ -16498,7 +16560,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "bcc": { "type": "array", @@ -16506,12 +16569,14 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", @@ -16519,7 +16584,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -16625,7 +16691,8 @@ "data": { "type": "object", "description": "Additional key-value pair data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -16670,7 +16737,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -16776,7 +16844,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -16784,7 +16853,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -16792,77 +16862,92 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "title": { "type": "string", "description": "Title for push notification.", - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -16873,7 +16958,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -17049,7 +17135,8 @@ "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17203,7 +17290,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "users": { "type": "array", @@ -17211,7 +17299,8 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "targets": { "type": "array", @@ -17219,22 +17308,26 @@ "x-example": null, "items": { "type": "string" - } + }, + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -17787,7 +17880,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17945,7 +18039,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -17970,7 +18065,8 @@ "sandbox": { "type": "boolean", "description": "Use APNS sandbox environment.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -18111,12 +18207,14 @@ "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18266,12 +18364,14 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -18358,7 +18458,8 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18383,7 +18484,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18481,12 +18583,14 @@ "isEuRegion": { "type": "boolean", "description": "Set as EU region.", - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18598,7 +18702,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18686,7 +18791,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -18803,7 +18909,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18891,7 +18998,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19018,7 +19126,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19106,7 +19215,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19356,7 +19466,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19532,7 +19643,8 @@ "port": { "type": "integer", "description": "SMTP port.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -19559,7 +19671,8 @@ "autoTLS": { "type": "boolean", "description": "Enable SMTP AutoTLS feature.", - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -19589,7 +19702,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19681,7 +19795,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19769,7 +19884,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -19876,7 +19992,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19964,7 +20081,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -20071,7 +20189,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20159,7 +20278,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -20266,7 +20386,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20354,7 +20475,8 @@ "enabled": { "type": "boolean", "description": "Set as enabled.", - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20970,7 +21092,8 @@ "name": { "type": "string", "description": "Topic Name.", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", @@ -20978,7 +21101,8 @@ "x-example": "[\"any\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -22508,17 +22632,20 @@ "installCommand": { "type": "string", "description": "Install Commands.", - "x-example": "<INSTALL_COMMAND>" + "x-example": "<INSTALL_COMMAND>", + "x-nullable": true }, "buildCommand": { "type": "string", "description": "Build Commands.", - "x-example": "<BUILD_COMMAND>" + "x-example": "<BUILD_COMMAND>", + "x-nullable": true }, "outputDirectory": { "type": "string", "description": "Output Directory.", - "x-example": "<OUTPUT_DIRECTORY>" + "x-example": "<OUTPUT_DIRECTORY>", + "x-nullable": true }, "code": { "type": "string", @@ -23643,12 +23770,14 @@ "value": { "type": "string", "description": "Variable value. Max length: 8192 chars.", - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -23878,7 +24007,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -24073,7 +24203,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "fileSecurity": { "type": "boolean", @@ -24369,7 +24500,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } }, "required": [ @@ -24539,7 +24671,8 @@ "name": { "type": "string", "description": "Name of the file", - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", @@ -24547,7 +24680,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true } } } @@ -26008,7 +26142,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -26194,7 +26329,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rowSecurity": { "type": "boolean", @@ -26473,7 +26609,8 @@ "default": { "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -26593,7 +26730,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26818,7 +26956,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26923,7 +27062,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -27043,7 +27183,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27156,7 +27297,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -27285,7 +27427,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27391,17 +27534,20 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27515,12 +27661,14 @@ "min": { "type": "number", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -27531,7 +27679,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27636,17 +27785,20 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27760,12 +27912,14 @@ "min": { "type": "integer", "description": "Minimum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -27776,7 +27930,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27881,7 +28036,8 @@ "default": { "type": "string", "description": "Default value. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -28001,7 +28157,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28236,7 +28393,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28470,7 +28628,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28704,7 +28863,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28821,12 +28981,14 @@ "key": { "type": "string", "description": "Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -28948,7 +29110,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -29074,12 +29237,14 @@ "size": { "type": "integer", "description": "Maximum size of the string column.", - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29184,7 +29349,8 @@ "default": { "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -29304,7 +29470,8 @@ "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29605,12 +29772,14 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -30279,7 +30448,8 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "rows": { "type": "array", @@ -30292,7 +30462,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30420,7 +30591,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -30526,7 +30698,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30624,7 +30797,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30879,12 +31053,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30995,12 +31171,14 @@ "x-example": "[\"read(\"any\")\"]", "items": { "type": "string" - } + }, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31096,7 +31274,8 @@ "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31216,12 +31395,14 @@ "min": { "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31341,12 +31522,14 @@ "max": { "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -32959,12 +33142,14 @@ "email": { "type": "string", "description": "User email.", - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/app/config/specs/swagger2-1.8.x-client.json b/app/config/specs/swagger2-1.8.x-client.json index a304a7cb1a..1594f816ef 100644 --- a/app/config/specs/swagger2-1.8.x-client.json +++ b/app/config/specs/swagger2-1.8.x-client.json @@ -6400,6 +6400,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6417,7 +6418,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6657,6 +6659,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6665,7 +6668,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -6771,6 +6775,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6779,7 +6784,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6870,7 +6876,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6982,13 +6989,15 @@ "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -7100,13 +7109,15 @@ "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -7305,7 +7316,8 @@ "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", "default": null, - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -8417,13 +8429,15 @@ "type": "string", "description": "Name of the file", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", "description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9516,6 +9530,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9533,7 +9548,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9766,6 +9782,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9774,7 +9791,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9876,6 +9894,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9884,7 +9903,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9974,7 +9994,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10085,13 +10106,15 @@ "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10202,13 +10225,15 @@ "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 158b308f87..5f05314818 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -7168,6 +7168,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -7350,6 +7351,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -7625,7 +7627,8 @@ "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7743,7 +7746,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7965,7 +7969,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8069,7 +8074,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -8187,7 +8193,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8300,7 +8307,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -8428,7 +8436,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8533,19 +8542,22 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8656,13 +8668,15 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8675,7 +8689,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8779,19 +8794,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8902,13 +8920,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8921,7 +8941,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9025,7 +9046,8 @@ "type": "string", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -9143,7 +9165,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9360,7 +9383,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9576,7 +9600,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9792,7 +9817,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9909,13 +9935,15 @@ "type": "string", "description": "Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -10038,7 +10066,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -10163,13 +10192,15 @@ "type": "integer", "description": "Maximum size of the string attribute.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10273,7 +10304,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -10391,7 +10423,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10679,13 +10712,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10955,6 +10990,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -10972,7 +11008,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11101,7 +11138,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11206,7 +11244,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11302,7 +11341,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11542,6 +11582,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11550,7 +11591,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11656,6 +11698,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11664,7 +11707,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11755,7 +11799,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11957,13 +12002,15 @@ "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -12075,13 +12122,15 @@ "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -14896,7 +14945,8 @@ "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", "default": null, - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -15409,13 +15459,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17532,7 +17584,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17615,6 +17668,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17624,6 +17678,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17633,6 +17688,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17641,31 +17697,36 @@ "type": "string", "description": "Email Subject.", "default": null, - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", "description": "Array of target IDs to be added as CC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17675,6 +17736,7 @@ "description": "Array of target IDs to be added as BCC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17683,13 +17745,15 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", "description": "Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17806,7 +17870,8 @@ "type": "object", "description": "Additional key-value pair data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -17860,7 +17925,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -17965,6 +18031,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17974,6 +18041,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17983,6 +18051,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17991,85 +18060,99 @@ "type": "string", "description": "Title for push notification.", "default": null, - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", "default": null, - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", "default": null, - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", "default": null, - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", "default": null, - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", "default": null, - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", "default": null, - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -18081,7 +18164,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -18263,7 +18347,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -18411,6 +18496,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -18420,6 +18506,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -18429,6 +18516,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -18437,19 +18525,22 @@ "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -18989,7 +19080,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19144,7 +19236,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -19174,7 +19267,8 @@ "type": "boolean", "description": "Use APNS sandbox environment.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19317,13 +19411,15 @@ "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19470,13 +19566,15 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -19569,7 +19667,8 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19599,7 +19698,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19698,13 +19798,15 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19827,7 +19929,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19914,7 +20017,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -20043,7 +20147,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20130,7 +20235,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20271,7 +20377,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20358,7 +20465,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20626,7 +20734,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20800,7 +20909,8 @@ "type": "integer", "description": "SMTP port.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -20831,7 +20941,8 @@ "type": "boolean", "description": "Enable SMTP AutoTLS feature.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -20867,7 +20978,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -20966,7 +21078,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21053,7 +21166,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -21170,7 +21284,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21257,7 +21372,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -21374,7 +21490,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21461,7 +21578,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -21578,7 +21696,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21665,7 +21784,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -22265,13 +22385,15 @@ "type": "string", "description": "Topic Name.", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", "description": "An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.", "default": null, "x-example": "[\"any\"]", + "x-nullable": true, "items": { "type": "string" } @@ -24332,13 +24454,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only projects can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -26651,6 +26775,7 @@ "description": "Key scopes list. Maximum of 100 scopes are allowed.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -26659,7 +26784,8 @@ "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26817,6 +26943,7 @@ "description": "Key scopes list. Maximum of 100 events are allowed.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -26825,7 +26952,8 @@ "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27015,19 +27143,22 @@ "type": "string", "description": "Provider app ID. Max length: 256 chars.", "default": null, - "x-example": "<APP_ID>" + "x-example": "<APP_ID>", + "x-nullable": true }, "secret": { "type": "string", "description": "Provider secret key. Max length: 512 chars.", "default": null, - "x-example": "<SECRET>" + "x-example": "<SECRET>", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Provider status. Set to 'false' to disable new session creation.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -33273,13 +33404,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -33504,6 +33637,7 @@ "description": "An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -33702,6 +33836,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -34146,13 +34281,15 @@ "type": "string", "description": "Name of the file", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", "description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -35796,6 +35933,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -35976,6 +36114,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -36248,7 +36387,8 @@ "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -36365,7 +36505,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36585,7 +36726,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36688,7 +36830,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -36805,7 +36948,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36917,7 +37061,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -37044,7 +37189,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37148,19 +37294,22 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37270,13 +37419,15 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -37289,7 +37440,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37392,19 +37544,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37514,13 +37669,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -37533,7 +37690,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37636,7 +37794,8 @@ "type": "string", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37753,7 +37912,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37968,7 +38128,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38182,7 +38343,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38396,7 +38558,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38512,13 +38675,15 @@ "type": "string", "description": "Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -38640,7 +38805,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -38764,13 +38930,15 @@ "type": "integer", "description": "Maximum size of the string column.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38873,7 +39041,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -38990,7 +39159,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -39275,13 +39445,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -39993,6 +40165,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -40010,7 +40183,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40134,7 +40308,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -40238,7 +40413,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40333,7 +40509,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40566,6 +40743,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -40574,7 +40752,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40676,6 +40855,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -40684,7 +40864,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40774,7 +40955,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40974,13 +41156,15 @@ "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -41091,13 +41275,15 @@ "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -42915,13 +43101,15 @@ "type": "string", "description": "User email.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", "default": null, - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index 8b972be590..15606799ea 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -6620,6 +6620,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6804,6 +6805,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -7082,7 +7084,8 @@ "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7201,7 +7204,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7425,7 +7429,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7530,7 +7535,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -7649,7 +7655,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7763,7 +7770,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -7892,7 +7900,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7998,19 +8007,22 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8122,13 +8134,15 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8141,7 +8155,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8246,19 +8261,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8370,13 +8388,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8389,7 +8409,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8494,7 +8515,8 @@ "type": "string", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8613,7 +8635,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8832,7 +8855,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9050,7 +9074,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9268,7 +9293,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9386,13 +9412,15 @@ "type": "string", "description": "Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -9516,7 +9544,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -9642,13 +9671,15 @@ "type": "integer", "description": "Maximum size of the string attribute.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9753,7 +9784,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -9872,7 +9904,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10163,13 +10196,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10445,6 +10480,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -10462,7 +10498,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10593,7 +10630,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -10699,7 +10737,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10796,7 +10835,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11041,6 +11081,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11049,7 +11090,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11157,6 +11199,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11165,7 +11208,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11258,7 +11302,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11372,13 +11417,15 @@ "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11492,13 +11539,15 @@ "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -13721,7 +13770,8 @@ "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", "default": null, - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -14163,13 +14213,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -16331,7 +16383,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -16415,6 +16468,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16424,6 +16478,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16433,6 +16488,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16441,31 +16497,36 @@ "type": "string", "description": "Email Subject.", "default": null, - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", "description": "Array of target IDs to be added as CC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16475,6 +16536,7 @@ "description": "Array of target IDs to be added as BCC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16483,13 +16545,15 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", "description": "Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16607,7 +16671,8 @@ "type": "object", "description": "Additional key-value pair data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -16661,7 +16726,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -16767,6 +16833,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16776,6 +16843,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16785,6 +16853,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16793,85 +16862,99 @@ "type": "string", "description": "Title for push notification.", "default": null, - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", "default": null, - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", "default": null, - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", "default": null, - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", "default": null, - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", "default": null, - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", "default": null, - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -16883,7 +16966,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -17068,7 +17152,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17219,6 +17304,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17228,6 +17314,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17237,6 +17324,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17245,19 +17333,22 @@ "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -17805,7 +17896,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17963,7 +18055,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -17993,7 +18086,8 @@ "type": "boolean", "description": "Use APNS sandbox environment.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -18139,13 +18233,15 @@ "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18295,13 +18391,15 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -18395,7 +18493,8 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18425,7 +18524,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18525,13 +18625,15 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18655,7 +18757,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18743,7 +18846,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -18873,7 +18977,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18961,7 +19066,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19103,7 +19209,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19191,7 +19298,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19462,7 +19570,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19639,7 +19748,8 @@ "type": "integer", "description": "SMTP port.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -19670,7 +19780,8 @@ "type": "boolean", "description": "Enable SMTP AutoTLS feature.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -19706,7 +19817,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19806,7 +19918,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19894,7 +20007,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -20012,7 +20126,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20100,7 +20215,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -20218,7 +20334,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20306,7 +20423,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -20424,7 +20542,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20512,7 +20631,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -21120,13 +21240,15 @@ "type": "string", "description": "Topic Name.", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", "description": "An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.", "default": null, "x-example": "[\"any\"]", + "x-nullable": true, "items": { "type": "string" } @@ -23782,13 +23904,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -24016,6 +24140,7 @@ "description": "An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -24216,6 +24341,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -24669,13 +24795,15 @@ "type": "string", "description": "Name of the file", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", "description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -26103,6 +26231,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -26285,6 +26414,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -26560,7 +26690,8 @@ "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -26678,7 +26809,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26900,7 +27032,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27004,7 +27137,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -27122,7 +27256,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27235,7 +27370,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -27363,7 +27499,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27468,19 +27605,22 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27591,13 +27731,15 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -27610,7 +27752,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27714,19 +27857,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27837,13 +27983,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -27856,7 +28004,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27960,7 +28109,8 @@ "type": "string", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -28078,7 +28228,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28295,7 +28446,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28511,7 +28663,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28727,7 +28880,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28844,13 +28998,15 @@ "type": "string", "description": "Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -28973,7 +29129,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -29098,13 +29255,15 @@ "type": "integer", "description": "Maximum size of the string column.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29208,7 +29367,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -29326,7 +29486,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29614,13 +29775,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -30261,6 +30424,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -30278,7 +30442,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30404,7 +30569,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -30509,7 +30675,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30605,7 +30772,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30843,6 +31011,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -30851,7 +31020,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30955,6 +31125,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -30963,7 +31134,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31055,7 +31227,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31168,13 +31341,15 @@ "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31287,13 +31462,15 @@ "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -32870,13 +33047,15 @@ "type": "string", "description": "User email.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", "default": null, - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index a304a7cb1a..1594f816ef 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -6400,6 +6400,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6417,7 +6418,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6657,6 +6659,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6665,7 +6668,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -6771,6 +6775,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6779,7 +6784,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6870,7 +6876,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -6982,13 +6989,15 @@ "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -7100,13 +7109,15 @@ "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -7305,7 +7316,8 @@ "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", "default": null, - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -8417,13 +8429,15 @@ "type": "string", "description": "Name of the file", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", "description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9516,6 +9530,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9533,7 +9548,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9766,6 +9782,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9774,7 +9791,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9876,6 +9894,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -9884,7 +9903,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -9974,7 +9994,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10085,13 +10106,15 @@ "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10202,13 +10225,15 @@ "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 158b308f87..5f05314818 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -7168,6 +7168,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -7350,6 +7351,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -7625,7 +7627,8 @@ "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7743,7 +7746,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7965,7 +7969,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8069,7 +8074,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -8187,7 +8193,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8300,7 +8307,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -8428,7 +8436,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8533,19 +8542,22 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8656,13 +8668,15 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8675,7 +8689,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8779,19 +8794,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8902,13 +8920,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8921,7 +8941,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9025,7 +9046,8 @@ "type": "string", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -9143,7 +9165,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9360,7 +9383,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9576,7 +9600,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9792,7 +9817,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9909,13 +9935,15 @@ "type": "string", "description": "Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -10038,7 +10066,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -10163,13 +10192,15 @@ "type": "integer", "description": "Maximum size of the string attribute.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10273,7 +10304,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -10391,7 +10423,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10679,13 +10712,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10955,6 +10990,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -10972,7 +11008,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11101,7 +11138,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11206,7 +11244,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11302,7 +11341,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11542,6 +11582,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11550,7 +11591,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11656,6 +11698,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11664,7 +11707,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11755,7 +11799,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11957,13 +12002,15 @@ "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -12075,13 +12122,15 @@ "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -14896,7 +14945,8 @@ "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", "default": null, - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -15409,13 +15459,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17532,7 +17584,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17615,6 +17668,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17624,6 +17678,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17633,6 +17688,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17641,31 +17697,36 @@ "type": "string", "description": "Email Subject.", "default": null, - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", "description": "Array of target IDs to be added as CC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17675,6 +17736,7 @@ "description": "Array of target IDs to be added as BCC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17683,13 +17745,15 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", "description": "Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17806,7 +17870,8 @@ "type": "object", "description": "Additional key-value pair data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -17860,7 +17925,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -17965,6 +18031,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17974,6 +18041,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17983,6 +18051,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17991,85 +18060,99 @@ "type": "string", "description": "Title for push notification.", "default": null, - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", "default": null, - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", "default": null, - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", "default": null, - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", "default": null, - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", "default": null, - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", "default": null, - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -18081,7 +18164,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -18263,7 +18347,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -18411,6 +18496,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -18420,6 +18506,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -18429,6 +18516,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -18437,19 +18525,22 @@ "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -18989,7 +19080,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19144,7 +19236,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -19174,7 +19267,8 @@ "type": "boolean", "description": "Use APNS sandbox environment.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19317,13 +19411,15 @@ "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19470,13 +19566,15 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -19569,7 +19667,8 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19599,7 +19698,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19698,13 +19798,15 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -19827,7 +19929,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19914,7 +20017,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -20043,7 +20147,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20130,7 +20235,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20271,7 +20377,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20358,7 +20465,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -20626,7 +20734,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20800,7 +20909,8 @@ "type": "integer", "description": "SMTP port.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -20831,7 +20941,8 @@ "type": "boolean", "description": "Enable SMTP AutoTLS feature.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -20867,7 +20978,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -20966,7 +21078,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21053,7 +21166,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -21170,7 +21284,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21257,7 +21372,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -21374,7 +21490,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21461,7 +21578,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -21578,7 +21696,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -21665,7 +21784,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -22265,13 +22385,15 @@ "type": "string", "description": "Topic Name.", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", "description": "An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.", "default": null, "x-example": "[\"any\"]", + "x-nullable": true, "items": { "type": "string" } @@ -24332,13 +24454,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only projects can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -26651,6 +26775,7 @@ "description": "Key scopes list. Maximum of 100 scopes are allowed.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -26659,7 +26784,8 @@ "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26817,6 +26943,7 @@ "description": "Key scopes list. Maximum of 100 events are allowed.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -26825,7 +26952,8 @@ "type": "string", "description": "Expiration time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27015,19 +27143,22 @@ "type": "string", "description": "Provider app ID. Max length: 256 chars.", "default": null, - "x-example": "<APP_ID>" + "x-example": "<APP_ID>", + "x-nullable": true }, "secret": { "type": "string", "description": "Provider secret key. Max length: 512 chars.", "default": null, - "x-example": "<SECRET>" + "x-example": "<SECRET>", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Provider status. Set to 'false' to disable new session creation.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -33273,13 +33404,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -33504,6 +33637,7 @@ "description": "An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -33702,6 +33836,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -34146,13 +34281,15 @@ "type": "string", "description": "Name of the file", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", "description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -35796,6 +35933,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -35976,6 +36114,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -36248,7 +36387,8 @@ "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -36365,7 +36505,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36585,7 +36726,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36688,7 +36830,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -36805,7 +36948,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -36917,7 +37061,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -37044,7 +37189,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37148,19 +37294,22 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37270,13 +37419,15 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -37289,7 +37440,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37392,19 +37544,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37514,13 +37669,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -37533,7 +37690,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37636,7 +37794,8 @@ "type": "string", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -37753,7 +37912,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -37968,7 +38128,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38182,7 +38343,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38396,7 +38558,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38512,13 +38675,15 @@ "type": "string", "description": "Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -38640,7 +38805,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -38764,13 +38930,15 @@ "type": "integer", "description": "Maximum size of the string column.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -38873,7 +39041,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -38990,7 +39159,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -39275,13 +39445,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -39993,6 +40165,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -40010,7 +40183,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40134,7 +40308,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -40238,7 +40413,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40333,7 +40509,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40566,6 +40743,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -40574,7 +40752,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40676,6 +40855,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -40684,7 +40864,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40774,7 +40955,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -40974,13 +41156,15 @@ "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -41091,13 +41275,15 @@ "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -42915,13 +43101,15 @@ "type": "string", "description": "User email.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", "default": null, - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 8b972be590..15606799ea 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -6620,6 +6620,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -6804,6 +6805,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -7082,7 +7084,8 @@ "type": "boolean", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -7201,7 +7204,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7425,7 +7429,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7530,7 +7535,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -7649,7 +7655,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7763,7 +7770,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -7892,7 +7900,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -7998,19 +8007,22 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8122,13 +8134,15 @@ "type": "number", "description": "Minimum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -8141,7 +8155,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8246,19 +8261,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8370,13 +8388,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -8389,7 +8409,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8494,7 +8515,8 @@ "type": "string", "description": "Default value. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -8613,7 +8635,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -8832,7 +8855,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9050,7 +9074,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9268,7 +9293,8 @@ "type": "string", "description": "New attribute key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9386,13 +9412,15 @@ "type": "string", "description": "Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -9516,7 +9544,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -9642,13 +9671,15 @@ "type": "integer", "description": "Maximum size of the string attribute.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -9753,7 +9784,8 @@ "type": "string", "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -9872,7 +9904,8 @@ "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -10163,13 +10196,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Attribute Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -10445,6 +10480,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -10462,7 +10498,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10593,7 +10630,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -10699,7 +10737,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -10796,7 +10835,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11041,6 +11081,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11049,7 +11090,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -11157,6 +11199,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -11165,7 +11208,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11258,7 +11302,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11372,13 +11417,15 @@ "type": "number", "description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -11492,13 +11539,15 @@ "type": "number", "description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -13721,7 +13770,8 @@ "type": "string", "description": "Scheduled execution time in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.", "default": null, - "x-example": "<SCHEDULED_AT>" + "x-example": "<SCHEDULED_AT>", + "x-nullable": true } } } @@ -14163,13 +14213,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only functions can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -16331,7 +16383,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -16415,6 +16468,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16424,6 +16478,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16433,6 +16488,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16441,31 +16497,36 @@ "type": "string", "description": "Email Subject.", "default": null, - "x-example": "<SUBJECT>" + "x-example": "<SUBJECT>", + "x-nullable": true }, "content": { "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "html": { "type": "boolean", "description": "Is content of type HTML", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "cc": { "type": "array", "description": "Array of target IDs to be added as CC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16475,6 +16536,7 @@ "description": "Array of target IDs to be added as BCC.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16483,13 +16545,15 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "attachments": { "type": "array", "description": "Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16607,7 +16671,8 @@ "type": "object", "description": "Additional key-value pair data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", @@ -16661,7 +16726,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", @@ -16767,6 +16833,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16776,6 +16843,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16785,6 +16853,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -16793,85 +16862,99 @@ "type": "string", "description": "Title for push notification.", "default": null, - "x-example": "<TITLE>" + "x-example": "<TITLE>", + "x-nullable": true }, "body": { "type": "string", "description": "Body for push notification.", "default": null, - "x-example": "<BODY>" + "x-example": "<BODY>", + "x-nullable": true }, "data": { "type": "object", "description": "Additional Data for push notification.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "action": { "type": "string", "description": "Action for push notification.", "default": null, - "x-example": "<ACTION>" + "x-example": "<ACTION>", + "x-nullable": true }, "image": { "type": "string", "description": "Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.", "default": null, - "x-example": "<ID1:ID2>" + "x-example": "<ID1:ID2>", + "x-nullable": true }, "icon": { "type": "string", "description": "Icon for push notification. Available only for Android and Web platforms.", "default": null, - "x-example": "<ICON>" + "x-example": "<ICON>", + "x-nullable": true }, "sound": { "type": "string", "description": "Sound for push notification. Available only for Android and iOS platforms.", "default": null, - "x-example": "<SOUND>" + "x-example": "<SOUND>", + "x-nullable": true }, "color": { "type": "string", "description": "Color for push notification. Available only for Android platforms.", "default": null, - "x-example": "<COLOR>" + "x-example": "<COLOR>", + "x-nullable": true }, "tag": { "type": "string", "description": "Tag for push notification. Available only for Android platforms.", "default": null, - "x-example": "<TAG>" + "x-example": "<TAG>", + "x-nullable": true }, "badge": { "type": "integer", "description": "Badge for push notification. Available only for iOS platforms.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "contentAvailable": { "type": "boolean", "description": "If set to true, the notification will be delivered in the background. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "critical": { "type": "boolean", "description": "If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "priority": { "type": "string", @@ -16883,7 +16966,8 @@ "high" ], "x-enum-name": "MessagePriority", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true } } } @@ -17068,7 +17152,8 @@ "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -17219,6 +17304,7 @@ "description": "List of Topic IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17228,6 +17314,7 @@ "description": "List of User IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17237,6 +17324,7 @@ "description": "List of Targets IDs.", "default": null, "x-example": null, + "x-nullable": true, "items": { "type": "string" } @@ -17245,19 +17333,22 @@ "type": "string", "description": "Email Content.", "default": null, - "x-example": "<CONTENT>" + "x-example": "<CONTENT>", + "x-nullable": true }, "draft": { "type": "boolean", "description": "Is message a draft", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "scheduledAt": { "type": "string", "description": "Scheduled delivery time for message in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. DateTime value must be in future.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -17805,7 +17896,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -17963,7 +18055,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "authKey": { "type": "string", @@ -17993,7 +18086,8 @@ "type": "boolean", "description": "Use APNS sandbox environment.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -18139,13 +18233,15 @@ "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18295,13 +18391,15 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "serviceAccountJSON": { "type": "object", "description": "FCM service account JSON.", "default": {}, - "x-example": "{}" + "x-example": "{}", + "x-nullable": true } } } @@ -18395,7 +18493,8 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18425,7 +18524,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18525,13 +18625,15 @@ "type": "boolean", "description": "Set as EU region.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "enabled": { "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "fromName": { "type": "string", @@ -18655,7 +18757,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18743,7 +18846,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "templateId": { "type": "string", @@ -18873,7 +18977,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -18961,7 +19066,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19103,7 +19209,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19191,7 +19298,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -19462,7 +19570,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19639,7 +19748,8 @@ "type": "integer", "description": "SMTP port.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "username": { "type": "string", @@ -19670,7 +19780,8 @@ "type": "boolean", "description": "Enable SMTP AutoTLS feature.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "mailer": { "type": "string", @@ -19706,7 +19817,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } } } @@ -19806,7 +19918,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -19894,7 +20007,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "customerId": { "type": "string", @@ -20012,7 +20126,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20100,7 +20215,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "username": { "type": "string", @@ -20218,7 +20334,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20306,7 +20423,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "accountSid": { "type": "string", @@ -20424,7 +20542,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -20512,7 +20631,8 @@ "type": "boolean", "description": "Set as enabled.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "apiKey": { "type": "string", @@ -21120,13 +21240,15 @@ "type": "string", "description": "Topic Name.", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "subscribe": { "type": "array", "description": "An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.", "default": null, "x-example": "[\"any\"]", + "x-nullable": true, "items": { "type": "string" } @@ -23782,13 +23904,15 @@ "type": "string", "description": "Variable value. Max length: 8192 chars.", "default": null, - "x-example": "<VALUE>" + "x-example": "<VALUE>", + "x-nullable": true }, "secret": { "type": "boolean", "description": "Secret variables can be updated or deleted, but only sites can read them during build and runtime.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true } }, "required": [ @@ -24016,6 +24140,7 @@ "description": "An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -24216,6 +24341,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -24669,13 +24795,15 @@ "type": "string", "description": "Name of the file", "default": null, - "x-example": "<NAME>" + "x-example": "<NAME>", + "x-nullable": true }, "permissions": { "type": "array", "description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -26103,6 +26231,7 @@ "description": "An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -26285,6 +26414,7 @@ "description": "An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -26560,7 +26690,8 @@ "type": "boolean", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": false + "x-example": false, + "x-nullable": true }, "array": { "type": "boolean", @@ -26678,7 +26809,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -26900,7 +27032,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27004,7 +27137,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -27122,7 +27256,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27235,7 +27370,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -27363,7 +27499,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27468,19 +27605,22 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", "description": "Default value. Cannot be set when required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27591,13 +27731,15 @@ "type": "number", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "number", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "number", @@ -27610,7 +27752,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27714,19 +27857,22 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -27837,13 +27983,15 @@ "type": "integer", "description": "Minimum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "max": { "type": "integer", "description": "Maximum value", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "default": { "type": "integer", @@ -27856,7 +28004,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -27960,7 +28109,8 @@ "type": "string", "description": "Default value. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -28078,7 +28228,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28295,7 +28446,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28511,7 +28663,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28727,7 +28880,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -28844,13 +28998,15 @@ "type": "string", "description": "Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "twoWayKey": { "type": "string", "description": "Two Way Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "onDelete": { "type": "string", @@ -28973,7 +29129,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "<DEFAULT>" + "x-example": "<DEFAULT>", + "x-nullable": true }, "array": { "type": "boolean", @@ -29098,13 +29255,15 @@ "type": "integer", "description": "Maximum size of the string column.", "default": null, - "x-example": 1 + "x-example": 1, + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29208,7 +29367,8 @@ "type": "string", "description": "Default value for column when not provided. Cannot be set when column is required.", "default": null, - "x-example": "https:\/\/example.com" + "x-example": "https:\/\/example.com", + "x-nullable": true }, "array": { "type": "boolean", @@ -29326,7 +29486,8 @@ "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } }, "required": [ @@ -29614,13 +29775,15 @@ "setNull" ], "x-enum-name": "RelationMutate", - "x-enum-keys": [] + "x-enum-keys": [], + "x-nullable": true }, "newKey": { "type": "string", "description": "New Column Key.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true } } } @@ -30261,6 +30424,7 @@ "description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -30278,7 +30442,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30404,7 +30569,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } }, "required": [ @@ -30509,7 +30675,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30605,7 +30772,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30843,6 +31011,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -30851,7 +31020,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -30955,6 +31125,7 @@ "description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": null, "x-example": "[\"read(\"any\")\"]", + "x-nullable": true, "items": { "type": "string" } @@ -30963,7 +31134,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31055,7 +31227,8 @@ "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31168,13 +31341,15 @@ "type": "number", "description": "Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -31287,13 +31462,15 @@ "type": "number", "description": "Maximum value for the column. If the current value is greater than this value, an error will be thrown.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "transactionId": { "type": "string", "description": "Transaction ID for staging the operation.", "default": null, - "x-example": "<TRANSACTION_ID>" + "x-example": "<TRANSACTION_ID>", + "x-nullable": true } } } @@ -32870,13 +33047,15 @@ "type": "string", "description": "User email.", "default": null, - "x-example": "email@example.com" + "x-example": "email@example.com", + "x-nullable": true }, "phone": { "type": "string", "description": "Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.", "default": null, - "x-example": "+12065550100" + "x-example": "+12065550100", + "x-nullable": true }, "password": { "type": "string", diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index 88f22c2594..d8f50a5578 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -21,6 +21,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; class Delete extends Action { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php index d18a81c1af..4c8b599c8c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php @@ -10,6 +10,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; +use Utopia\Validator\Nullable; class Delete extends DocumentDelete { From 74492ded447f8eae3b66709504b02f74688477d3 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Mon, 10 Nov 2025 11:35:25 +0530 Subject: [PATCH 090/167] update description --- .../Platform/Modules/Databases/Http/TablesDB/Tables/Update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php index a6cb611870..a4bfb5bf23 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php @@ -57,7 +57,7 @@ class Update extends CollectionUpdate ->param('tableId', '', new UID(), 'Table ID.') ->param('name', null, new Text(128), 'Table name. Max length: 128 chars.') ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('rowSecurity', false, new Boolean(true), 'Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) + ->param('rowSecurity', false, new Boolean(true), 'Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) ->param('enabled', true, new Boolean(), 'Is table enabled? When set to \'disabled\', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.', true) ->inject('response') ->inject('dbForProject') From b06460b5626a45ef7f2fd4ae31a521e3e0cbf14b Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Mon, 10 Nov 2025 14:19:26 +0530 Subject: [PATCH 091/167] chore: release cli and php --- app/config/platforms.php | 4 +- composer.lock | 136 +++++++++--------- .../examples/avatars/get-screenshot.md | 34 +++++ docs/sdks/cli/CHANGELOG.md | 4 + docs/sdks/php/CHANGELOG.md | 6 + 5 files changed, 117 insertions(+), 67 deletions(-) create mode 100644 docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md diff --git a/app/config/platforms.php b/app/config/platforms.php index 361ec6b935..c60274294b 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -226,7 +226,7 @@ return [ [ 'key' => 'cli', 'name' => 'Command Line', - 'version' => '11.1.0', + 'version' => '11.1.1', 'url' => 'https://github.com/appwrite/sdk-for-cli', 'package' => 'https://www.npmjs.com/package/appwrite-cli', 'enabled' => true, @@ -281,7 +281,7 @@ return [ [ 'key' => 'php', 'name' => 'PHP', - 'version' => '17.5.0', + 'version' => '17.6.0', 'url' => 'https://github.com/appwrite/sdk-for-php', 'package' => 'https://packagist.org/packages/appwrite/appwrite', 'enabled' => true, diff --git a/composer.lock b/composer.lock index 87eaf28a3e..bff2111d85 100644 --- a/composer.lock +++ b/composer.lock @@ -2673,16 +2673,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.4", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", "shasum": "" }, "require": { @@ -2749,7 +2749,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "source": "https://github.com/symfony/http-client/tree/v7.3.6" }, "funding": [ { @@ -2769,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-11-05T17:41:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -3176,16 +3176,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -3239,7 +3239,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -3250,12 +3250,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "tbachert/spi", @@ -3840,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.1.5", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "76568b81f25d89fc1e0c53f0370f139130eeb939" + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/76568b81f25d89fc1e0c53f0370f139130eeb939", - "reference": "76568b81f25d89fc1e0c53f0370f139130eeb939", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", "shasum": "" }, "require": { @@ -3892,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.1.5" + "source": "https://github.com/utopia-php/database/tree/3.2.0" }, - "time": "2025-11-05T10:17:55+00:00" + "time": "2025-11-06T05:41:54+00:00" }, { "name": "utopia-php/detector", @@ -3943,22 +3947,24 @@ }, { "name": "utopia-php/dns", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/utopia-php/dns.git", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a" + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/dns/zipball/d6eca184883262bdcb4261e57491c91b16079b9a", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a", + "url": "https://api.github.com/repos/utopia-php/dns/zipball/1e6b4bac735329c9e5ec69a6a5d899ec2d050707", + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707", "shasum": "" }, "require": { "php": ">=8.3", "utopia-php/console": "0.0.*", - "utopia-php/telemetry": "0.1.*" + "utopia-php/domains": "0.9.*", + "utopia-php/telemetry": "0.1.*", + "utopia-php/validators": "^0.0.2" }, "require-dev": { "laravel/pint": "1.25.*", @@ -3992,9 +3998,9 @@ ], "support": { "issues": "https://github.com/utopia-php/dns/issues", - "source": "https://github.com/utopia-php/dns/tree/1.1.0" + "source": "https://github.com/utopia-php/dns/tree/1.1.3" }, - "time": "2025-11-03T22:49:02+00:00" + "time": "2025-11-06T19:08:29+00:00" }, { "name": "utopia-php/domains", @@ -5377,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.1", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "cd712674e34136f706e9170641ed6f4ce160e772" + "reference": "7a34a2c31266408838400cf1b263671dc6b4637a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cd712674e34136f706e9170641ed6f4ce160e772", - "reference": "cd712674e34136f706e9170641ed6f4ce160e772", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/7a34a2c31266408838400cf1b263671dc6b4637a", + "reference": "7a34a2c31266408838400cf1b263671dc6b4637a", "shasum": "" }, "require": { @@ -5422,9 +5428,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.5.1" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.2" }, - "time": "2025-11-04T09:55:47+00:00" + "time": "2025-11-10T07:56:53+00:00" }, { "name": "doctrine/annotations", @@ -6077,24 +6083,24 @@ }, { "name": "phpbench/container", - "version": "2.2.2", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/phpbench/container.git", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33" + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", "shasum": "" }, "require": { "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0" + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", + "php-cs-fixer/shim": "^3.89", "phpstan/phpstan": "^0.12.52", "phpunit/phpunit": "^8" }, @@ -6122,22 +6128,22 @@ "description": "Simple, configurable, service container.", "support": { "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.2" + "source": "https://github.com/phpbench/container/tree/2.2.3" }, - "time": "2023-10-30T13:38:26+00:00" + "time": "2025-11-06T09:05:13+00:00" }, { "name": "phpbench/phpbench", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878", + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878", "shasum": "" }, "require": { @@ -6152,26 +6158,26 @@ "phpbench/container": "^2.2", "psr/log": "^1.1 || ^2.0 || ^3.0", "seld/jsonlint": "^1.1", - "symfony/console": "^6.1 || ^7.0", - "symfony/filesystem": "^6.1 || ^7.0", - "symfony/finder": "^6.1 || ^7.0", - "symfony/options-resolver": "^6.1 || ^7.0", - "symfony/process": "^6.1 || ^7.0", + "symfony/console": "^6.1 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.1 || ^7.0 || ^8.0", + "symfony/finder": "^6.1 || ^7.0 || ^8.0", + "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0", + "symfony/process": "^6.1 || ^7.0 || ^8.0", "webmozart/glob": "^4.6" }, "require-dev": { "dantleech/invoke": "^2.0", "ergebnis/composer-normalize": "^2.39", - "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", + "php-cs-fixer/shim": "^3.9", "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^10.4 || ^11.0", "rector/rector": "^1.2", - "symfony/error-handler": "^6.1 || ^7.0", - "symfony/var-dumper": "^6.1 || ^7.0" + "symfony/error-handler": "^6.1 || ^7.0 || ^8.0", + "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0" }, "suggest": { "ext-xdebug": "For Xdebug profiling extension." @@ -6214,7 +6220,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.2" + "source": "https://github.com/phpbench/phpbench/tree/1.4.3" }, "funding": [ { @@ -6222,7 +6228,7 @@ "type": "github" } ], - "time": "2025-10-26T14:21:59+00:00" + "time": "2025-11-06T19:07:31+00:00" }, { "name": "phpstan/phpstan", @@ -7871,16 +7877,16 @@ }, { "name": "symfony/console", - "version": "v7.3.5", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", "shasum": "" }, "require": { @@ -7945,7 +7951,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.5" + "source": "https://github.com/symfony/console/tree/v7.3.6" }, "funding": [ { @@ -7965,20 +7971,20 @@ "type": "tidelift" } ], - "time": "2025-10-14T15:46:26+00:00" + "time": "2025-11-04T01:21:42+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.2", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", "shasum": "" }, "require": { @@ -8015,7 +8021,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" }, "funding": [ { @@ -8035,7 +8041,7 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:47+00:00" + "time": "2025-11-05T09:52:27+00:00" }, { "name": "symfony/finder", diff --git a/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..6d416ebad3 --- /dev/null +++ b/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md @@ -0,0 +1,34 @@ +<?php + +use Appwrite\Client; +use Appwrite\Services\Avatars; + +$client = (new Client()) + ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('<YOUR_PROJECT_ID>') // Your project ID + ->setSession(''); // The user session to authenticate with + +$avatars = new Avatars($client); + +$result = $avatars->getScreenshot( + url: 'https://example.com', + headers: [], // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: ::LIGHT(), // optional + userAgent: '<USER_AGENT>', // optional + fullpage: false, // optional + locale: '<LOCALE>', // optional + timezone: ::AFRICAABIDJAN(), // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: ::JPG() // optional +); \ No newline at end of file diff --git a/docs/sdks/cli/CHANGELOG.md b/docs/sdks/cli/CHANGELOG.md index ac1624401c..8e50441769 100644 --- a/docs/sdks/cli/CHANGELOG.md +++ b/docs/sdks/cli/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 11.1.1 + +* Fix duplicate `enums` during type generation by prefixing them with table name. For example, `enum MyEnum` will now be generated as `enum MyTableMyEnum` to avoid conflicts. + ## 11.1.0 * Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance diff --git a/docs/sdks/php/CHANGELOG.md b/docs/sdks/php/CHANGELOG.md index 6e8d4d7545..1b74b0ee5a 100644 --- a/docs/sdks/php/CHANGELOG.md +++ b/docs/sdks/php/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 17.6.0 + +* Fix duplicate methods issue (e.g., `updateMFA` and `updateMfa`) causing build and runtime errors +* Add support for `getScreenshot` method to `Avatars` service +* Add `Output`, `Theme` and `Timezone` enums + ## 17.5.0 * Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance From 2ff0ae61c847384f3190af4350dafc6d9bbef700 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Mon, 10 Nov 2025 15:00:09 +0530 Subject: [PATCH 092/167] update php --- app/config/platforms.php | 2 +- docs/sdks/php/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/platforms.php b/app/config/platforms.php index c60274294b..e183ab1bcb 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -281,7 +281,7 @@ return [ [ 'key' => 'php', 'name' => 'PHP', - 'version' => '17.6.0', + 'version' => '18.0.0', 'url' => 'https://github.com/appwrite/sdk-for-php', 'package' => 'https://packagist.org/packages/appwrite/appwrite', 'enabled' => true, diff --git a/docs/sdks/php/CHANGELOG.md b/docs/sdks/php/CHANGELOG.md index 1b74b0ee5a..8727bf6b97 100644 --- a/docs/sdks/php/CHANGELOG.md +++ b/docs/sdks/php/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## 17.6.0 +## 18.0.0 * Fix duplicate methods issue (e.g., `updateMFA` and `updateMfa`) causing build and runtime errors * Add support for `getScreenshot` method to `Avatars` service From 4a148e6ef9313a014b04c1741b374c5f52e40a90 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Mon, 10 Nov 2025 15:06:22 +0530 Subject: [PATCH 093/167] remove broken execute --- src/Appwrite/Platform/Tasks/SDKs.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index cf4f107e8e..f587e0f946 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -259,8 +259,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND } if ($createRelease) { - Console::execute('git config --global user.email "$GIT_EMAIL"', stdin: '', stdout: '', stderr: ''); - $releaseVersion = $language['version']; $repoName = $language['gitUserName'] . '/' . $language['gitRepoName']; From 4dc700927ef20e460fca262caddf03c73603c8ae Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Mon, 10 Nov 2025 15:39:54 +0530 Subject: [PATCH 094/167] fix: examples --- composer.lock | 12 ++++++------ .../server-php/examples/avatars/get-screenshot.md | 9 ++++++--- .../databases/create-relationship-attribute.md | 1 + .../databases/update-relationship-attribute.md | 1 + .../examples/functions/create-execution.md | 1 + .../1.8.x/server-php/examples/functions/create.md | 4 ++-- .../examples/functions/get-deployment-download.md | 1 + .../1.8.x/server-php/examples/functions/update.md | 3 ++- .../server-php/examples/health/get-failed-jobs.md | 4 ++-- .../server-php/examples/messaging/create-push.md | 1 + .../examples/messaging/create-smtp-provider.md | 1 + .../server-php/examples/messaging/update-push.md | 1 + .../examples/messaging/update-smtp-provider.md | 1 + .../1.8.x/server-php/examples/sites/create.md | 11 ++++++----- .../examples/sites/get-deployment-download.md | 1 + .../1.8.x/server-php/examples/sites/update.md | 10 ++++++---- .../server-php/examples/storage/create-bucket.md | 3 ++- .../server-php/examples/storage/get-file-preview.md | 2 ++ .../server-php/examples/storage/update-bucket.md | 3 ++- .../examples/tablesdb/create-relationship-column.md | 1 + .../examples/tablesdb/update-relationship-column.md | 1 + .../server-php/examples/users/create-sha-user.md | 1 + 22 files changed, 48 insertions(+), 25 deletions(-) diff --git a/composer.lock b/composer.lock index bff2111d85..fe245d7837 100644 --- a/composer.lock +++ b/composer.lock @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.2", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "7a34a2c31266408838400cf1b263671dc6b4637a" + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/7a34a2c31266408838400cf1b263671dc6b4637a", - "reference": "7a34a2c31266408838400cf1b263671dc6b4637a", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", "shasum": "" }, "require": { @@ -5428,9 +5428,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.5.2" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.3" }, - "time": "2025-11-10T07:56:53+00:00" + "time": "2025-11-10T09:50:41+00:00" }, { "name": "doctrine/annotations", diff --git a/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md index 6d416ebad3..b9dfd23862 100644 --- a/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-php/examples/avatars/get-screenshot.md @@ -2,6 +2,9 @@ use Appwrite\Client; use Appwrite\Services\Avatars; +use Appwrite\Enums\Theme; +use Appwrite\Enums\Timezone; +use Appwrite\Enums\Output; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -16,11 +19,11 @@ $result = $avatars->getScreenshot( viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: ::LIGHT(), // optional + theme: Theme::LIGHT(), // optional userAgent: '<USER_AGENT>', // optional fullpage: false, // optional locale: '<LOCALE>', // optional - timezone: ::AFRICAABIDJAN(), // optional + timezone: Timezone::AFRICAABIDJAN(), // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -30,5 +33,5 @@ $result = $avatars->getScreenshot( width: 0, // optional height: 0, // optional quality: -1, // optional - output: ::JPG() // optional + output: Output::JPG() // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/databases/create-relationship-attribute.md b/docs/examples/1.8.x/server-php/examples/databases/create-relationship-attribute.md index caccd36031..551fe17a9d 100644 --- a/docs/examples/1.8.x/server-php/examples/databases/create-relationship-attribute.md +++ b/docs/examples/1.8.x/server-php/examples/databases/create-relationship-attribute.md @@ -3,6 +3,7 @@ use Appwrite\Client; use Appwrite\Services\Databases; use Appwrite\Enums\RelationshipType; +use Appwrite\Enums\RelationMutate; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/databases/update-relationship-attribute.md b/docs/examples/1.8.x/server-php/examples/databases/update-relationship-attribute.md index 01783cf3bf..a4d6888711 100644 --- a/docs/examples/1.8.x/server-php/examples/databases/update-relationship-attribute.md +++ b/docs/examples/1.8.x/server-php/examples/databases/update-relationship-attribute.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Databases; +use Appwrite\Enums\RelationMutate; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/functions/create-execution.md b/docs/examples/1.8.x/server-php/examples/functions/create-execution.md index cd11b5ea6e..9c12e87374 100644 --- a/docs/examples/1.8.x/server-php/examples/functions/create-execution.md +++ b/docs/examples/1.8.x/server-php/examples/functions/create-execution.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Functions; +use Appwrite\Enums\ExecutionMethod; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/functions/create.md b/docs/examples/1.8.x/server-php/examples/functions/create.md index 3d37b8068e..f7176871bd 100644 --- a/docs/examples/1.8.x/server-php/examples/functions/create.md +++ b/docs/examples/1.8.x/server-php/examples/functions/create.md @@ -2,7 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Functions; -use Appwrite\Enums\; +use Appwrite\Enums\Runtime; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -14,7 +14,7 @@ $functions = new Functions($client); $result = $functions->create( functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: ::NODE145(), + runtime: Runtime::NODE145(), execute: ["any"], // optional events: [], // optional schedule: '', // optional diff --git a/docs/examples/1.8.x/server-php/examples/functions/get-deployment-download.md b/docs/examples/1.8.x/server-php/examples/functions/get-deployment-download.md index 7b3e18751e..a06f97b662 100644 --- a/docs/examples/1.8.x/server-php/examples/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-php/examples/functions/get-deployment-download.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Functions; +use Appwrite\Enums\DeploymentDownloadType; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/functions/update.md b/docs/examples/1.8.x/server-php/examples/functions/update.md index ea8d863ae5..da5ee88931 100644 --- a/docs/examples/1.8.x/server-php/examples/functions/update.md +++ b/docs/examples/1.8.x/server-php/examples/functions/update.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Functions; +use Appwrite\Enums\Runtime; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -13,7 +14,7 @@ $functions = new Functions($client); $result = $functions->update( functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: ::NODE145(), // optional + runtime: Runtime::NODE145(), // optional execute: ["any"], // optional events: [], // optional schedule: '', // optional diff --git a/docs/examples/1.8.x/server-php/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/server-php/examples/health/get-failed-jobs.md index 02959db3b5..63bc1c83f2 100644 --- a/docs/examples/1.8.x/server-php/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-php/examples/health/get-failed-jobs.md @@ -2,7 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Health; -use Appwrite\Enums\; +use Appwrite\Enums\Name; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -12,6 +12,6 @@ $client = (new Client()) $health = new Health($client); $result = $health->getFailedJobs( - name: ::V1DATABASE(), + name: Name::V1DATABASE(), threshold: null // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/messaging/create-push.md b/docs/examples/1.8.x/server-php/examples/messaging/create-push.md index 51fc0d0a92..614c758c80 100644 --- a/docs/examples/1.8.x/server-php/examples/messaging/create-push.md +++ b/docs/examples/1.8.x/server-php/examples/messaging/create-push.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Messaging; +use Appwrite\Enums\MessagePriority; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/messaging/create-smtp-provider.md b/docs/examples/1.8.x/server-php/examples/messaging/create-smtp-provider.md index 017f20cc15..953bbcf44f 100644 --- a/docs/examples/1.8.x/server-php/examples/messaging/create-smtp-provider.md +++ b/docs/examples/1.8.x/server-php/examples/messaging/create-smtp-provider.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Messaging; +use Appwrite\Enums\SmtpEncryption; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/messaging/update-push.md b/docs/examples/1.8.x/server-php/examples/messaging/update-push.md index 05a51783c9..0fea9a135f 100644 --- a/docs/examples/1.8.x/server-php/examples/messaging/update-push.md +++ b/docs/examples/1.8.x/server-php/examples/messaging/update-push.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Messaging; +use Appwrite\Enums\MessagePriority; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/messaging/update-smtp-provider.md b/docs/examples/1.8.x/server-php/examples/messaging/update-smtp-provider.md index 3bc80d2789..495f332131 100644 --- a/docs/examples/1.8.x/server-php/examples/messaging/update-smtp-provider.md +++ b/docs/examples/1.8.x/server-php/examples/messaging/update-smtp-provider.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Messaging; +use Appwrite\Enums\SmtpEncryption; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/sites/create.md b/docs/examples/1.8.x/server-php/examples/sites/create.md index 4a1c3a4fcb..6f1fc5ac27 100644 --- a/docs/examples/1.8.x/server-php/examples/sites/create.md +++ b/docs/examples/1.8.x/server-php/examples/sites/create.md @@ -2,8 +2,9 @@ use Appwrite\Client; use Appwrite\Services\Sites; -use Appwrite\Enums\; -use Appwrite\Enums\; +use Appwrite\Enums\Framework; +use Appwrite\Enums\BuildRuntime; +use Appwrite\Enums\Adapter; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -15,15 +16,15 @@ $sites = new Sites($client); $result = $sites->create( siteId: '<SITE_ID>', name: '<NAME>', - framework: ::ANALOG(), - buildRuntime: ::NODE145(), + framework: Framework::ANALOG(), + buildRuntime: BuildRuntime::NODE145(), enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: '<INSTALL_COMMAND>', // optional buildCommand: '<BUILD_COMMAND>', // optional outputDirectory: '<OUTPUT_DIRECTORY>', // optional - adapter: ::STATIC(), // optional + adapter: Adapter::STATIC(), // optional installationId: '<INSTALLATION_ID>', // optional fallbackFile: '<FALLBACK_FILE>', // optional providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // optional diff --git a/docs/examples/1.8.x/server-php/examples/sites/get-deployment-download.md b/docs/examples/1.8.x/server-php/examples/sites/get-deployment-download.md index 91c6b6e52a..61fad0bd74 100644 --- a/docs/examples/1.8.x/server-php/examples/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-php/examples/sites/get-deployment-download.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Sites; +use Appwrite\Enums\DeploymentDownloadType; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/sites/update.md b/docs/examples/1.8.x/server-php/examples/sites/update.md index f2ca54a987..d2a6c9d256 100644 --- a/docs/examples/1.8.x/server-php/examples/sites/update.md +++ b/docs/examples/1.8.x/server-php/examples/sites/update.md @@ -2,7 +2,9 @@ use Appwrite\Client; use Appwrite\Services\Sites; -use Appwrite\Enums\; +use Appwrite\Enums\Framework; +use Appwrite\Enums\BuildRuntime; +use Appwrite\Enums\Adapter; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -14,15 +16,15 @@ $sites = new Sites($client); $result = $sites->update( siteId: '<SITE_ID>', name: '<NAME>', - framework: ::ANALOG(), + framework: Framework::ANALOG(), enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: '<INSTALL_COMMAND>', // optional buildCommand: '<BUILD_COMMAND>', // optional outputDirectory: '<OUTPUT_DIRECTORY>', // optional - buildRuntime: ::NODE145(), // optional - adapter: ::STATIC(), // optional + buildRuntime: BuildRuntime::NODE145(), // optional + adapter: Adapter::STATIC(), // optional fallbackFile: '<FALLBACK_FILE>', // optional installationId: '<INSTALLATION_ID>', // optional providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // optional diff --git a/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md index 2e7cc1d15c..3d4f717e4d 100644 --- a/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Storage; +use Appwrite\Enums\Compression; use Appwrite\Permission; use Appwrite\Role; @@ -20,7 +21,7 @@ $result = $storage->createBucket( enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: [], // optional - compression: ::NONE(), // optional + compression: Compression::NONE(), // optional encryption: false, // optional antivirus: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/storage/get-file-preview.md b/docs/examples/1.8.x/server-php/examples/storage/get-file-preview.md index 0b65fc326a..aaa15a22fb 100644 --- a/docs/examples/1.8.x/server-php/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-php/examples/storage/get-file-preview.md @@ -2,6 +2,8 @@ use Appwrite\Client; use Appwrite\Services\Storage; +use Appwrite\Enums\ImageGravity; +use Appwrite\Enums\ImageFormat; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md index 819798cb95..77f4262c2d 100644 --- a/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Storage; +use Appwrite\Enums\Compression; use Appwrite\Permission; use Appwrite\Role; @@ -20,7 +21,7 @@ $result = $storage->updateBucket( enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: [], // optional - compression: ::NONE(), // optional + compression: Compression::NONE(), // optional encryption: false, // optional antivirus: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/tablesdb/create-relationship-column.md b/docs/examples/1.8.x/server-php/examples/tablesdb/create-relationship-column.md index 031d1fd1aa..7f9a06cc03 100644 --- a/docs/examples/1.8.x/server-php/examples/tablesdb/create-relationship-column.md +++ b/docs/examples/1.8.x/server-php/examples/tablesdb/create-relationship-column.md @@ -3,6 +3,7 @@ use Appwrite\Client; use Appwrite\Services\TablesDB; use Appwrite\Enums\RelationshipType; +use Appwrite\Enums\RelationMutate; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/tablesdb/update-relationship-column.md b/docs/examples/1.8.x/server-php/examples/tablesdb/update-relationship-column.md index 834dc18cee..cc2e2ccaef 100644 --- a/docs/examples/1.8.x/server-php/examples/tablesdb/update-relationship-column.md +++ b/docs/examples/1.8.x/server-php/examples/tablesdb/update-relationship-column.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\TablesDB; +use Appwrite\Enums\RelationMutate; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint diff --git a/docs/examples/1.8.x/server-php/examples/users/create-sha-user.md b/docs/examples/1.8.x/server-php/examples/users/create-sha-user.md index 0b9a27ed8e..812bcd5eb5 100644 --- a/docs/examples/1.8.x/server-php/examples/users/create-sha-user.md +++ b/docs/examples/1.8.x/server-php/examples/users/create-sha-user.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Users; +use Appwrite\Enums\PasswordHash; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint From 057397197bbc5ebed5663e25862f50f8394389bd Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Mon, 10 Nov 2025 18:20:31 +0530 Subject: [PATCH 095/167] update to 18.0.1 --- app/config/platforms.php | 2 +- docs/sdks/php/CHANGELOG.md | 4 ++++ src/Appwrite/Platform/Tasks/SDKs.php | 17 +++++++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/config/platforms.php b/app/config/platforms.php index e183ab1bcb..5d72a8914c 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -281,7 +281,7 @@ return [ [ 'key' => 'php', 'name' => 'PHP', - 'version' => '18.0.0', + 'version' => '18.0.1', 'url' => 'https://github.com/appwrite/sdk-for-php', 'package' => 'https://packagist.org/packages/appwrite/appwrite', 'enabled' => true, diff --git a/docs/sdks/php/CHANGELOG.md b/docs/sdks/php/CHANGELOG.md index 8727bf6b97..14a26e441d 100644 --- a/docs/sdks/php/CHANGELOG.md +++ b/docs/sdks/php/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 18.0.1 + +* Fix `TablesDB` service to use correct file name + ## 18.0.0 * Fix duplicate methods issue (e.g., `updateMFA` and `updateMfa`) causing build and runtime errors diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index f587e0f946..d3c605655f 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -427,16 +427,21 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND mkdir -p ' . $target . ' && \ cd ' . $target . ' && \ git init && \ + git config core.ignorecase false && \ + git config pull.rebase false && \ git remote add origin ' . $gitUrl . ' && \ git fetch origin && \ - git checkout ' . $repoBranch . ' || git checkout -b ' . $repoBranch . ' && \ + (git checkout -f ' . $repoBranch . ' 2>/dev/null || git checkout -b ' . $repoBranch . ') && \ git pull origin ' . $repoBranch . ' && \ - git checkout ' . $gitBranch . ' || git checkout -b ' . $gitBranch . ' && \ - git fetch origin ' . $gitBranch . ' || git push -u origin ' . $gitBranch . ' && \ - git pull origin ' . $gitBranch . ' && \ - find . -mindepth 1 ! -path "./.git*" -delete && \ + (git checkout -f ' . $gitBranch . ' 2>/dev/null || git checkout -b ' . $gitBranch . ') && \ + (git fetch origin ' . $gitBranch . ' 2>/dev/null || git push -u origin ' . $gitBranch . ') && \ + git reset --hard origin/' . $gitBranch . ' 2>/dev/null || true && \ + (test -d .github && cp -r .github /tmp/.github-backup-$$ || true) && \ + git rm -rf --cached . && \ + git clean -fdx -e .git -e .github && \ cp -r ' . $result . '/. ' . $target . '/ && \ - git add . && \ + (test -d /tmp/.github-backup-$$ && cp -r /tmp/.github-backup-$$/.github . && rm -rf /tmp/.github-backup-$$ || true) && \ + git add -A && \ git commit -m "' . $message . '" && \ git push -u origin ' . $gitBranch . ' '); From 5afae248aead81a96410d1b06ba0a73e2108ffd9 Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Mon, 10 Nov 2025 15:00:18 +0200 Subject: [PATCH 096/167] Test Update --- composer.json | 1 - tests/e2e/Services/Account/AccountBase.php | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 9694c2dc51..62abce9ca2 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,6 @@ "utopia-php/framework": "0.33.*", "utopia-php/fetch": "0.4.*", "utopia-php/image": "0.8.*", - "utopia-php/emails": "0.6.*", "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.20.*", diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index d51632c6c9..9f35932700 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -29,7 +29,7 @@ trait AccountBase ]); $id = $response['body']['$id']; - var_dump($response['body']); + $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']); $this->assertNotEmpty($response['body']['$id']); @@ -41,8 +41,11 @@ trait AccountBase $this->assertNotEmpty($response['body']['accessedAt']); $this->assertArrayHasKey('targets', $response['body']); $this->assertEquals($email, $response['body']['targets'][0]['identifier']); - $this->assertEquals('shmuel', 'fogel'); - + $this->assertArrayNotHasKey('emailCanonical', $response['body']); + $this->assertArrayNotHasKey('emailIsFree', $response['body']); + $this->assertArrayNotHasKey('emailIsDisposable', $response['body']); + $this->assertArrayNotHasKey('emailIsCorporate', $response['body']); + $this->assertArrayNotHasKey('emailIsCanonical', $response['body']); /** * Test for FAILURE From c784cf950bb9dd749e1337e629fdabcd006b2474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Mon, 10 Nov 2025 16:20:48 +0100 Subject: [PATCH 097/167] Add variables suggestion --- app/controllers/api/vcs.php | 63 ++++++++ composer.lock | 140 +++++++++--------- .../Response/Model/DetectionFramework.php | 7 + .../Response/Model/DetectionRuntime.php | 7 + .../Response/Model/ProviderRepository.php | 7 + 5 files changed, 157 insertions(+), 67 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index a6e72bf476..fd4d04cbd0 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -14,6 +14,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Installations; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Vcs\Comment; +use Swoole\Coroutine\WaitGroup; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; @@ -963,6 +964,37 @@ App::post('/v1/vcs/github/installations/:installationId/detections') throw new Exception(Exception::FUNCTION_RUNTIME_NOT_DETECTED); } } + + $wg = new WaitGroup(); + $envNames = []; + foreach ($files as $file) { + if (!(\str_starts_with($file, '.env'))) { + continue; + } + + $wg->add(); + go(function () use ($github, $owner, $repositoryName, $providerRootDirectory, $file, $wg, &$envNames) { + try { + $contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/' . $file); + $envFile = $contentResponse['content'] ?? ''; + + $envLines = \explode("\n", $envFile); + foreach ($envLines as $line) { + $parts = \explode('=', $line, 2); + $envName = \trim($parts[0] ?? ''); + if (!empty($envName)) { + $envNames[] = $envName; + } + } + } finally { + $wg->done(); + } + }); + } + $wg->wait(); + + $output->setAttribute('variables', \array_unique($envNames)); + $response->dynamic($output, $type === 'framework' ? Response::MODEL_DETECTION_FRAMEWORK : Response::MODEL_DETECTION_RUNTIME); }); @@ -1137,6 +1169,37 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') $repo['runtime'] = $runtimeWithVersion ?? ''; } } + + $wg = new WaitGroup(); + $envNames = []; + foreach ($files as $file) { + if (!(\str_starts_with($file, '.env'))) { + continue; + } + + $wg->add(); + go(function () use ($github, $repo, $file, $wg, &$envNames) { + try { + $contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], $file); + $envFile = $contentResponse['content'] ?? ''; + + $envLines = \explode("\n", $envFile); + foreach ($envLines as $line) { + $parts = \explode('=', $line, 2); + $envName = \trim($parts[0] ?? ''); + if (!empty($envName)) { + $envNames[] = $envName; + } + } + } finally { + $wg->done(); + } + }); + } + $wg->wait(); + + $repo['variables'] = \array_unique($envNames); + return $repo; }; }, $repos)); diff --git a/composer.lock b/composer.lock index 87eaf28a3e..d0ea4e720a 100644 --- a/composer.lock +++ b/composer.lock @@ -2673,16 +2673,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.4", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", "shasum": "" }, "require": { @@ -2749,7 +2749,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "source": "https://github.com/symfony/http-client/tree/v7.3.6" }, "funding": [ { @@ -2769,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-11-05T17:41:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -3176,16 +3176,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -3239,7 +3239,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -3250,12 +3250,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "tbachert/spi", @@ -3840,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.1.5", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "76568b81f25d89fc1e0c53f0370f139130eeb939" + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/76568b81f25d89fc1e0c53f0370f139130eeb939", - "reference": "76568b81f25d89fc1e0c53f0370f139130eeb939", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", "shasum": "" }, "require": { @@ -3892,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.1.5" + "source": "https://github.com/utopia-php/database/tree/3.2.0" }, - "time": "2025-11-05T10:17:55+00:00" + "time": "2025-11-06T05:41:54+00:00" }, { "name": "utopia-php/detector", @@ -3943,22 +3947,24 @@ }, { "name": "utopia-php/dns", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/utopia-php/dns.git", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a" + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/dns/zipball/d6eca184883262bdcb4261e57491c91b16079b9a", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a", + "url": "https://api.github.com/repos/utopia-php/dns/zipball/1e6b4bac735329c9e5ec69a6a5d899ec2d050707", + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707", "shasum": "" }, "require": { "php": ">=8.3", "utopia-php/console": "0.0.*", - "utopia-php/telemetry": "0.1.*" + "utopia-php/domains": "0.9.*", + "utopia-php/telemetry": "0.1.*", + "utopia-php/validators": "^0.0.2" }, "require-dev": { "laravel/pint": "1.25.*", @@ -3992,9 +3998,9 @@ ], "support": { "issues": "https://github.com/utopia-php/dns/issues", - "source": "https://github.com/utopia-php/dns/tree/1.1.0" + "source": "https://github.com/utopia-php/dns/tree/1.1.3" }, - "time": "2025-11-03T22:49:02+00:00" + "time": "2025-11-06T19:08:29+00:00" }, { "name": "utopia-php/domains", @@ -5377,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.1", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "cd712674e34136f706e9170641ed6f4ce160e772" + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cd712674e34136f706e9170641ed6f4ce160e772", - "reference": "cd712674e34136f706e9170641ed6f4ce160e772", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", "shasum": "" }, "require": { @@ -5422,9 +5428,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.5.1" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.3" }, - "time": "2025-11-04T09:55:47+00:00" + "time": "2025-11-10T09:50:41+00:00" }, { "name": "doctrine/annotations", @@ -6077,24 +6083,24 @@ }, { "name": "phpbench/container", - "version": "2.2.2", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/phpbench/container.git", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33" + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", "shasum": "" }, "require": { "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0" + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", + "php-cs-fixer/shim": "^3.89", "phpstan/phpstan": "^0.12.52", "phpunit/phpunit": "^8" }, @@ -6122,22 +6128,22 @@ "description": "Simple, configurable, service container.", "support": { "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.2" + "source": "https://github.com/phpbench/container/tree/2.2.3" }, - "time": "2023-10-30T13:38:26+00:00" + "time": "2025-11-06T09:05:13+00:00" }, { "name": "phpbench/phpbench", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878", + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878", "shasum": "" }, "require": { @@ -6152,26 +6158,26 @@ "phpbench/container": "^2.2", "psr/log": "^1.1 || ^2.0 || ^3.0", "seld/jsonlint": "^1.1", - "symfony/console": "^6.1 || ^7.0", - "symfony/filesystem": "^6.1 || ^7.0", - "symfony/finder": "^6.1 || ^7.0", - "symfony/options-resolver": "^6.1 || ^7.0", - "symfony/process": "^6.1 || ^7.0", + "symfony/console": "^6.1 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.1 || ^7.0 || ^8.0", + "symfony/finder": "^6.1 || ^7.0 || ^8.0", + "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0", + "symfony/process": "^6.1 || ^7.0 || ^8.0", "webmozart/glob": "^4.6" }, "require-dev": { "dantleech/invoke": "^2.0", "ergebnis/composer-normalize": "^2.39", - "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", + "php-cs-fixer/shim": "^3.9", "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^10.4 || ^11.0", "rector/rector": "^1.2", - "symfony/error-handler": "^6.1 || ^7.0", - "symfony/var-dumper": "^6.1 || ^7.0" + "symfony/error-handler": "^6.1 || ^7.0 || ^8.0", + "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0" }, "suggest": { "ext-xdebug": "For Xdebug profiling extension." @@ -6214,7 +6220,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.2" + "source": "https://github.com/phpbench/phpbench/tree/1.4.3" }, "funding": [ { @@ -6222,7 +6228,7 @@ "type": "github" } ], - "time": "2025-10-26T14:21:59+00:00" + "time": "2025-11-06T19:07:31+00:00" }, { "name": "phpstan/phpstan", @@ -7871,16 +7877,16 @@ }, { "name": "symfony/console", - "version": "v7.3.5", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", "shasum": "" }, "require": { @@ -7945,7 +7951,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.5" + "source": "https://github.com/symfony/console/tree/v7.3.6" }, "funding": [ { @@ -7965,20 +7971,20 @@ "type": "tidelift" } ], - "time": "2025-10-14T15:46:26+00:00" + "time": "2025-11-04T01:21:42+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.2", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", "shasum": "" }, "require": { @@ -8015,7 +8021,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" }, "funding": [ { @@ -8035,7 +8041,7 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:47+00:00" + "time": "2025-11-05T09:52:27+00:00" }, { "name": "symfony/finder", @@ -8891,7 +8897,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8915,5 +8921,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php index 9aeb885f76..899ad8766e 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php @@ -33,6 +33,13 @@ class DetectionFramework extends Model 'description' => 'Site Output Directory', 'default' => '', 'example' => 'dist', + ]) + ->addRule('variables', [ + 'type' => self::TYPE_STRING, + 'description' => 'Environment variables found in .env files', + 'default' => [], + 'array' => true, + 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php index 1c7c0be16b..20fde90491 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php @@ -27,6 +27,13 @@ class DetectionRuntime extends Model 'description' => 'Function install and build commands', 'default' => '', 'example' => 'npm install && npm run build', + ]) + ->addRule('variables', [ + 'type' => self::TYPE_STRING, + 'description' => 'Environment variables found in .env files', + 'default' => [], + 'array' => true, + 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php index eee058a05b..ddad0b059c 100644 --- a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php +++ b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php @@ -53,6 +53,13 @@ class ProviderRepository extends Model 'default' => APP_DATABASE_ATTRIBUTE_DATETIME, 'example' => APP_DATABASE_ATTRIBUTE_DATETIME, 'array' => false, + ]) + ->addRule('variables', [ + 'type' => self::TYPE_STRING, + 'description' => 'Environment variables found in .env files', + 'default' => [], + 'array' => true, + 'example' => ['PORT', 'NODE_ENV'], ]); } From 831a261c04e76f5a75089ec506dc89c70a1a16ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Mon, 10 Nov 2025 16:29:34 +0100 Subject: [PATCH 098/167] Sync unit tests with DNS lib validator --- tests/unit/Network/Validators/DNSTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/Network/Validators/DNSTest.php b/tests/unit/Network/Validators/DNSTest.php index 9f8928b87f..4611e00f4d 100644 --- a/tests/unit/Network/Validators/DNSTest.php +++ b/tests/unit/Network/Validators/DNSTest.php @@ -51,8 +51,10 @@ class DNSTest extends TestCase #[Retry(count: 5)] public function testCAA(): void { - $certainly = new DNS('certainly.com', Record::TYPE_CAA, 'ns1.digitalocean.com'); - $letsencrypt = new DNS('letsencrypt.org', Record::TYPE_CAA, 'ns1.digitalocean.com'); + $digitalOceanIp = '172.64.52.210'; // ping ns1.digitalocean.com + + $certainly = new DNS('certainly.com', Record::TYPE_CAA, $digitalOceanIp); + $letsencrypt = new DNS('letsencrypt.org', Record::TYPE_CAA, $digitalOceanIp); // No CAA record succeeds on main domain & subdomains for any issuer $this->assertEquals($certainly->isValid('caa.appwrite.org'), true); From 6096c42ff9fa9fd80b4a4dee355fe925ec1b1e82 Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Mon, 10 Nov 2025 17:30:40 +0200 Subject: [PATCH 099/167] More updates --- app/controllers/api/account.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 737f5c7016..41d746e7dc 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1612,6 +1612,12 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $failureRedirect(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */ } + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + try { $userId = ID::unique(); $user->setAttributes([ @@ -1639,7 +1645,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); + $user->removeAttribute('$sequence'); $userDoc = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); $dbForProject->createDocument('targets', new Document([ @@ -2015,6 +2027,12 @@ App::post('/v1/account/tokens/magic-url') $userId = $userId === 'unique()' ? ID::unique() : $userId; + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + $user->setAttributes([ '$id' => $userId, '$permissions' => [ @@ -2039,6 +2057,11 @@ App::post('/v1/account/tokens/magic-url') 'authenticators' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -2645,6 +2668,11 @@ App::post('/v1/account/tokens/phone') 'memberships' => null, 'search' => implode(' ', [$userId, $phone]), 'accessedAt' => DateTime::now(), + 'emailCanonical' => null, + 'emailIsCanonical' => null, + 'emailIsCorporate' => null, + 'emailIsDisposable' => null, + 'emailIsFree' => null, ]); $user->removeAttribute('$sequence'); From ce7f40dd34b4641e493d76c88f451e787952247c Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 08:16:09 +0200 Subject: [PATCH 100/167] Revert response model --- src/Appwrite/Utopia/Response/Model/User.php | 30 --------------------- 1 file changed, 30 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index c9ec5e36bc..672b8885a0 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -139,36 +139,6 @@ class User extends Model 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) - ->addRule('emailCanonical', [ - 'type' => self::TYPE_STRING, - 'description' => 'User email address.', - 'default' => null, - 'example' => 'john@appwrite.io', - ]) - ->addRule('emailIsCanonical', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'User email is canonical.', - 'default' => null, - 'example' => true, - ]) - ->addRule('emailIsCorporate', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'User email is corporate.', - 'default' => null, - 'example' => true, - ]) - ->addRule('emailIsDisposable', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'User email is disposable.', - 'default' => null, - 'example' => true, - ]) - ->addRule('emailIsFree', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'User email is free.', - 'default' => null, - 'example' => true, - ]) ; } From 74ff9a955b4cdd67cb30bfcb70ab1c0c930107fb Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Tue, 11 Nov 2025 20:20:08 +1300 Subject: [PATCH 101/167] Fix transactions + operators --- composer.lock | 124 +++--- .../Databases/Http/Databases/Action.php | 71 +++- .../Collections/Documents/Action.php | 54 +-- .../Http/Databases/Transactions/Action.php | 6 +- .../Http/Databases/Transactions/Update.php | 12 + .../Transactions/TransactionsBase.php | 376 ++++++++++++++++++ 6 files changed, 526 insertions(+), 117 deletions(-) diff --git a/composer.lock b/composer.lock index 8faa5a477c..cf92abde7c 100644 --- a/composer.lock +++ b/composer.lock @@ -2673,16 +2673,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.4", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", "shasum": "" }, "require": { @@ -2749,7 +2749,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "source": "https://github.com/symfony/http-client/tree/v7.3.6" }, "funding": [ { @@ -2769,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-11-05T17:41:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -3176,16 +3176,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -3239,7 +3239,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -3250,12 +3250,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "tbachert/spi", @@ -3840,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.1.2", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "b6541a9cd9b21786a5020327f582838afdb159aa" + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b6541a9cd9b21786a5020327f582838afdb159aa", - "reference": "b6541a9cd9b21786a5020327f582838afdb159aa", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", "shasum": "" }, "require": { @@ -3922,10 +3926,10 @@ "utopia" ], "support": { - "source": "https://github.com/utopia-php/database/tree/3.1.2", + "source": "https://github.com/utopia-php/database/tree/3.2.0", "issues": "https://github.com/utopia-php/database/issues" }, - "time": "2025-10-30T13:10:13+00:00" + "time": "2025-11-06T05:41:54+00:00" }, { "name": "utopia-php/detector", @@ -5468,16 +5472,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.0", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "42df22195d6457e52e4c819678168470b114a816" + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/42df22195d6457e52e4c819678168470b114a816", - "reference": "42df22195d6457e52e4c819678168470b114a816", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", "shasum": "" }, "require": { @@ -5513,9 +5517,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.5.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.3" }, - "time": "2025-10-31T10:10:25+00:00" + "time": "2025-11-10T09:50:41+00:00" }, { "name": "doctrine/annotations", @@ -6168,24 +6172,24 @@ }, { "name": "phpbench/container", - "version": "2.2.2", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/phpbench/container.git", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33" + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", "shasum": "" }, "require": { "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0" + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", + "php-cs-fixer/shim": "^3.89", "phpstan/phpstan": "^0.12.52", "phpunit/phpunit": "^8" }, @@ -6213,22 +6217,22 @@ "description": "Simple, configurable, service container.", "support": { "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.2" + "source": "https://github.com/phpbench/container/tree/2.2.3" }, - "time": "2023-10-30T13:38:26+00:00" + "time": "2025-11-06T09:05:13+00:00" }, { "name": "phpbench/phpbench", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878", + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878", "shasum": "" }, "require": { @@ -6243,26 +6247,26 @@ "phpbench/container": "^2.2", "psr/log": "^1.1 || ^2.0 || ^3.0", "seld/jsonlint": "^1.1", - "symfony/console": "^6.1 || ^7.0", - "symfony/filesystem": "^6.1 || ^7.0", - "symfony/finder": "^6.1 || ^7.0", - "symfony/options-resolver": "^6.1 || ^7.0", - "symfony/process": "^6.1 || ^7.0", + "symfony/console": "^6.1 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.1 || ^7.0 || ^8.0", + "symfony/finder": "^6.1 || ^7.0 || ^8.0", + "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0", + "symfony/process": "^6.1 || ^7.0 || ^8.0", "webmozart/glob": "^4.6" }, "require-dev": { "dantleech/invoke": "^2.0", "ergebnis/composer-normalize": "^2.39", - "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", + "php-cs-fixer/shim": "^3.9", "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^10.4 || ^11.0", "rector/rector": "^1.2", - "symfony/error-handler": "^6.1 || ^7.0", - "symfony/var-dumper": "^6.1 || ^7.0" + "symfony/error-handler": "^6.1 || ^7.0 || ^8.0", + "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0" }, "suggest": { "ext-xdebug": "For Xdebug profiling extension." @@ -6305,7 +6309,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.2" + "source": "https://github.com/phpbench/phpbench/tree/1.4.3" }, "funding": [ { @@ -6313,7 +6317,7 @@ "type": "github" } ], - "time": "2025-10-26T14:21:59+00:00" + "time": "2025-11-06T19:07:31+00:00" }, { "name": "phpstan/phpstan", @@ -7962,16 +7966,16 @@ }, { "name": "symfony/console", - "version": "v7.3.5", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", "shasum": "" }, "require": { @@ -8036,7 +8040,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.5" + "source": "https://github.com/symfony/console/tree/v7.3.6" }, "funding": [ { @@ -8056,20 +8060,20 @@ "type": "tidelift" } ], - "time": "2025-10-14T15:46:26+00:00" + "time": "2025-11-04T01:21:42+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.2", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", "shasum": "" }, "require": { @@ -8106,7 +8110,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" }, "funding": [ { @@ -8126,7 +8130,7 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:47+00:00" + "time": "2025-11-05T09:52:27+00:00" }, { "name": "symfony/finder", @@ -8982,7 +8986,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -9006,5 +9010,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php index 884b9c5589..63a7fe1559 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php @@ -2,9 +2,13 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases; -use Utopia\Platform\Action as UtopiaAction; +use Appwrite\Extend\Exception; +use Appwrite\Platform\Action as AppwriteAction; +use Utopia\Database\Database; +use Utopia\Database\Document; +use Utopia\Database\Operator; -class Action extends UtopiaAction +class Action extends AppwriteAction { private string $context = 'legacy'; @@ -13,11 +17,72 @@ class Action extends UtopiaAction return $this->context; } - public function setHttpPath(string $path): UtopiaAction + public function setHttpPath(string $path): AppwriteAction { if (\str_contains($path, '/tablesdb')) { $this->context = 'tablesdb'; } return parent::setHttpPath($path); } + + /** + * Parse operator strings in data array and convert them to Operator objects. + * + * @param array $data The data array that may contain operator JSON strings or arrays + * @param Document $collection The collection document to check for relationship attributes + * @return array The data array with operators converted to Operator objects + * @throws Exception If an operator string is invalid + */ + protected function parseOperators(array $data, Document $collection): array + { + $relationshipKeys = []; + foreach ($collection->getAttribute('attributes', []) as $attribute) { + if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { + $relationshipKeys[$attribute->getAttribute('key')] = true; + } + } + + foreach ($data as $key => $value) { + if (\str_starts_with($key, '$')) { + continue; + } + + if (isset($relationshipKeys[$key])) { + continue; + } + + // Handle operator as JSON string (from API requests) + if (\is_string($value)) { + $decoded = \json_decode($value, true); + + if ( + \is_array($decoded) && + isset($decoded['method']) && + \is_string($decoded['method']) && + Operator::isMethod($decoded['method']) + ) { + try { + $data[$key] = Operator::parse($value); + } catch (\Exception $e) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid operator for attribute "' . $key . '": ' . $e->getMessage()); + } + } + } + // Handle operator as array (from transaction logs after serialization) + elseif ( + \is_array($value) && + isset($value['method']) && + \is_string($value['method']) && + Operator::isMethod($value['method']) + ) { + try { + $data[$key] = Operator::parseOperator($value); + } catch (\Exception $e) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid operator for attribute "' . $key . '": ' . $e->getMessage()); + } + } + } + + return $data; + } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index c4c169b77c..08eea88e19 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -4,13 +4,12 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documen use Appwrite\Event\Event; use Appwrite\Extend\Exception; -use Appwrite\Platform\Action as AppwriteAction; +use Appwrite\Platform\Modules\Databases\Http\Databases\Action as DatabasesAction; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Operator; use Utopia\Database\Validator\Authorization; -abstract class Action extends AppwriteAction +abstract class Action extends DatabasesAction { /** * @var string|null The current context (either 'row' or 'document') @@ -22,7 +21,7 @@ abstract class Action extends AppwriteAction */ abstract protected function getResponseModel(): string; - public function setHttpPath(string $path): AppwriteAction + public function setHttpPath(string $path): DatabasesAction { if (str_contains($path, '/tablesdb/')) { $this->context = ROWS; @@ -339,53 +338,6 @@ abstract class Action extends AppwriteAction return true; } - /** - * Parse operator strings in data array and convert them to Operator objects. - * - * @param array $data The data array that may contain operator JSON strings - * @param Document $collection The collection document to check for relationship attributes - * @return array The data array with operators converted to Operator objects - * @throws Exception If an operator string is invalid - */ - protected function parseOperators(array $data, Document $collection): array - { - $relationshipKeys = []; - foreach ($collection->getAttribute('attributes', []) as $attribute) { - if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { - $relationshipKeys[$attribute->getAttribute('key')] = true; - } - } - - foreach ($data as $key => $value) { - if (\str_starts_with($key, '$')) { - continue; - } - - if (isset($relationshipKeys[$key])) { - continue; - } - - if (\is_string($value)) { - $decoded = \json_decode($value, true); - - if ( - \is_array($decoded) && - isset($decoded['method']) && - \is_string($decoded['method']) && - Operator::isMethod($decoded['method']) - ) { - try { - $data[$key] = Operator::parse($value); - } catch (\Exception $e) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid operator for attribute "' . $key . '": ' . $e->getMessage()); - } - } - } - } - - return $data; - } - /** * For triggering different queues for each document for a bulk documents * @param string $event diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php index 8915ae6141..e2a4491736 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php @@ -2,16 +2,16 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Transactions; -use Utopia\Platform\Action as UtopiaAction; +use Appwrite\Platform\Modules\Databases\Http\Databases\Action as DatabasesAction; -abstract class Action extends UtopiaAction +abstract class Action extends DatabasesAction { /** * The current API context (either 'table' or 'collection'). */ private ?string $context = COLLECTIONS; - public function setHttpPath(string $path): UtopiaAction + public function setHttpPath(string $path): DatabasesAction { if (\str_contains($path, '/tablesdb')) { $this->context = TABLES; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index 6e2bd63827..07c2f17426 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -149,6 +149,7 @@ class Update extends Action ])); $state = []; + $collections = []; foreach ($operations as $operation) { $databaseInternalId = $operation['databaseInternalId']; @@ -159,6 +160,17 @@ class Update extends Action $action = $operation['action']; $data = $operation['data']; + if (!isset($collections[$collectionId])) { + $collections[$collectionId] = Authorization::skip( + fn () => $dbForProject->getCollection($collectionId) + ); + } + $collection = $collections[$collectionId]; + + if (\is_array($data) && !empty($data)) { + $data = $this->parseOperators($data, $collection); + } + if ($action === 'delete' && $documentId && empty($data)) { $doc = $dbForProject->getDocument($collectionId, $documentId); if (!$doc->isEmpty()) { diff --git a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php index efa3b52cef..8ebc7582b3 100644 --- a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php +++ b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php @@ -5561,4 +5561,380 @@ trait TransactionsBase $this->assertEquals('Updated after upsert', $response['body']['name']); $this->assertEquals(20, $response['body']['counter']); } + + /** + * Test array operators in transactions using updateRow with transactionId + * This tests the fix for operators not being parsed when stored in transaction logs + */ + public function testArrayOperatorsWithUpdateRow(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'databaseId' => ID::unique(), + 'name' => 'ArrayOperatorsTestDB' + ]); + + $this->assertEquals(201, $database['headers']['status-code']); + $databaseId = $database['body']['$id']; + + // Create table with array column + $table = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'tableId' => ID::unique(), + 'name' => 'Items', + ]); + + $this->assertEquals(201, $table['headers']['status-code']); + $tableId = $table['body']['$id']; + + // Create array column + $column = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables/{$tableId}/columns/string", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'columnId' => 'items', + 'name' => 'Items', + 'size' => 255, + 'required' => false, + 'array' => true, + ]); + + $this->assertEquals(202, $column['headers']['status-code']); + sleep(2); // Wait for column to be created + + // Create initial row with some items + $row = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables/{$tableId}/rows", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'rowId' => 'test-row', + 'data' => [ + 'items' => ['item1', 'item2', 'item3', 'item4'] + ] + ]); + + $this->assertEquals(201, $row['headers']['status-code']); + $this->assertEquals(['item1', 'item2', 'item3', 'item4'], $row['body']['items']); + + // Create transaction + $transaction = $this->client->call(Client::METHOD_POST, '/tablesdb/transactions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(201, $transaction['headers']['status-code']); + $transactionId = $transaction['body']['$id']; + + // Test arrayRemove operator + $updateResponse = $this->client->call(Client::METHOD_PATCH, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/test-row", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'transactionId' => $transactionId, + 'data' => [ + 'items' => '{"method":"arrayRemove","attribute":"","values":["item2"]}' + ] + ]); + + $this->assertEquals(200, $updateResponse['headers']['status-code']); + + // Test arrayInsert operator + $updateResponse = $this->client->call(Client::METHOD_PATCH, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/test-row", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'transactionId' => $transactionId, + 'data' => [ + 'items' => '{"method":"arrayInsert","attribute":"","values":[2,"newItem"]}' + ] + ]); + + $this->assertEquals(200, $updateResponse['headers']['status-code']); + + // Commit transaction + $commitResponse = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'commit' => true + ]); + + $this->assertEquals(200, $commitResponse['headers']['status-code']); + + // Verify the operations were applied correctly + $row = $this->client->call(Client::METHOD_GET, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/test-row", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $row['headers']['status-code']); + // After removing item2: ['item1', 'item3', 'item4'] + // After inserting 'newItem' at index 2: ['item1', 'item3', 'newItem', 'item4'] + $this->assertEquals(['item1', 'item3', 'newItem', 'item4'], $row['body']['items']); + } + + /** + * Test array operators in transactions using createOperations + * This tests the fix for operators not being parsed in bulk operation creation + */ + public function testArrayOperatorsWithCreateOperations(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'databaseId' => ID::unique(), + 'name' => 'ArrayOperatorsBulkTestDB' + ]); + + $this->assertEquals(201, $database['headers']['status-code']); + $databaseId = $database['body']['$id']; + + // Create table with array column + $table = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'tableId' => ID::unique(), + 'name' => 'Tags', + ]); + + $this->assertEquals(201, $table['headers']['status-code']); + $tableId = $table['body']['$id']; + + // Create array column + $column = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables/{$tableId}/columns/string", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'columnId' => 'tags', + 'name' => 'Tags', + 'size' => 255, + 'required' => false, + 'array' => true, + ]); + + $this->assertEquals(202, $column['headers']['status-code']); + sleep(2); // Wait for column to be created + + // Create initial row + $row = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables/{$tableId}/rows", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'rowId' => 'doc1', + 'data' => [ + 'tags' => ['php', 'javascript', 'python', 'ruby'] + ] + ]); + + $this->assertEquals(201, $row['headers']['status-code']); + + // Create transaction + $transaction = $this->client->call(Client::METHOD_POST, '/tablesdb/transactions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(201, $transaction['headers']['status-code']); + $transactionId = $transaction['body']['$id']; + + // Create operations using bulk createOperations endpoint with array operators + $operations = $this->client->call(Client::METHOD_POST, "/tablesdb/transactions/{$transactionId}/operations", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'operations' => [ + [ + 'action' => 'update', + 'databaseId' => $databaseId, + 'tableId' => $tableId, + 'rowId' => 'doc1', + 'data' => [ + 'tags' => '{"method":"arrayRemove","attribute":"","values":["javascript"]}' + ] + ], + [ + 'action' => 'update', + 'databaseId' => $databaseId, + 'tableId' => $tableId, + 'rowId' => 'doc1', + 'data' => [ + 'tags' => '{"method":"arrayAppend","attribute":"","values":["go","rust"]}' + ] + ] + ] + ]); + + $this->assertEquals(201, $operations['headers']['status-code']); + $this->assertEquals(2, $operations['body']['operations']); + + // Commit transaction + $commitResponse = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'commit' => true + ]); + + $this->assertEquals(200, $commitResponse['headers']['status-code']); + + // Verify the operations were applied correctly + $row = $this->client->call(Client::METHOD_GET, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/doc1", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $row['headers']['status-code']); + // After removing 'javascript': ['php', 'python', 'ruby'] + // After appending ['go', 'rust']: ['php', 'python', 'ruby', 'go', 'rust'] + $this->assertEquals(['php', 'python', 'ruby', 'go', 'rust'], $row['body']['tags']); + } + + /** + * Test multiple array operators in a single transaction + * This tests all common array operators to ensure comprehensive coverage + */ + public function testMultipleArrayOperators(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'databaseId' => ID::unique(), + 'name' => 'MultipleOperatorsTestDB' + ]); + + $this->assertEquals(201, $database['headers']['status-code']); + $databaseId = $database['body']['$id']; + + // Create table + $table = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'tableId' => ID::unique(), + 'name' => 'Arrays', + ]); + + $this->assertEquals(201, $table['headers']['status-code']); + $tableId = $table['body']['$id']; + + // Create multiple array columns + $columns = [ + ['columnId' => 'list1', 'name' => 'List1'], + ['columnId' => 'list2', 'name' => 'List2'], + ['columnId' => 'list3', 'name' => 'List3'], + ]; + + foreach ($columns as $col) { + $column = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables/{$tableId}/columns/string", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'columnId' => $col['columnId'], + 'name' => $col['name'], + 'size' => 255, + 'required' => false, + 'array' => true, + ]); + $this->assertEquals(202, $column['headers']['status-code']); + } + + sleep(2); // Wait for columns to be created + + // Create initial row + $row = $this->client->call(Client::METHOD_POST, "/tablesdb/{$databaseId}/tables/{$tableId}/rows", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'rowId' => 'multi-ops', + 'data' => [ + 'list1' => ['a', 'b', 'c'], + 'list2' => ['x', 'y', 'z'], + 'list3' => ['1', '2', '3', '4', '5'] + ] + ]); + + $this->assertEquals(201, $row['headers']['status-code']); + + // Create transaction + $transaction = $this->client->call(Client::METHOD_POST, '/tablesdb/transactions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(201, $transaction['headers']['status-code']); + $transactionId = $transaction['body']['$id']; + + // Test arrayPrepend + $this->client->call(Client::METHOD_PATCH, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/multi-ops", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'transactionId' => $transactionId, + 'data' => [ + 'list1' => '{"method":"arrayPrepend","attribute":"","values":["z"]}' + ] + ]); + + // Test arrayAppend + $this->client->call(Client::METHOD_PATCH, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/multi-ops", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'transactionId' => $transactionId, + 'data' => [ + 'list2' => '{"method":"arrayAppend","attribute":"","values":["w"]}' + ] + ]); + + // Test arrayRemove + $this->client->call(Client::METHOD_PATCH, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/multi-ops", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'transactionId' => $transactionId, + 'data' => [ + 'list3' => '{"method":"arrayRemove","attribute":"","values":["3"]}' + ] + ]); + + // Commit transaction + $commitResponse = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'commit' => true + ]); + + $this->assertEquals(200, $commitResponse['headers']['status-code']); + + // Verify all operations were applied correctly + $row = $this->client->call(Client::METHOD_GET, "/tablesdb/{$databaseId}/tables/{$tableId}/rows/multi-ops", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $row['headers']['status-code']); + $this->assertEquals(['z', 'a', 'b', 'c'], $row['body']['list1'], 'arrayPrepend should add element at the beginning'); + $this->assertEquals(['x', 'y', 'z', 'w'], $row['body']['list2'], 'arrayAppend should add element at the end'); + $this->assertEquals(['1', '2', '4', '5'], $row['body']['list3'], 'arrayRemove should remove the element'); + } } From 94614d32d0c1a4dca3e109bdb015dfa84480ae96 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Tue, 11 Nov 2025 21:09:12 +1300 Subject: [PATCH 102/167] Handle deep nested ops --- .../Modules/Databases/Http/Databases/Action.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php index 63a7fe1559..f751fbab33 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php @@ -43,6 +43,13 @@ class Action extends AppwriteAction } foreach ($data as $key => $value) { + if (!\is_string($key)) { + if (\is_array($value)) { + $data[$key] = $this->parseOperators($value, $collection); + } + continue; + } + if (\str_starts_with($key, '$')) { continue; } @@ -81,6 +88,9 @@ class Action extends AppwriteAction throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid operator for attribute "' . $key . '": ' . $e->getMessage()); } } + elseif (\is_array($value)) { + $data[$key] = $this->parseOperators($value, $collection); + } } return $data; From 353e84bb7422a4761a2fcc4353af47aa96f84d14 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Tue, 11 Nov 2025 21:10:11 +1300 Subject: [PATCH 103/167] Fix keys --- .../Databases/TablesDB/Transactions/TransactionsBase.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php index 8ebc7582b3..cbdc7826a0 100644 --- a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php +++ b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php @@ -5600,8 +5600,7 @@ trait TransactionsBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'columnId' => 'items', - 'name' => 'Items', + 'key' => 'items', 'size' => 255, 'required' => false, 'array' => true, @@ -5719,8 +5718,7 @@ trait TransactionsBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'columnId' => 'tags', - 'name' => 'Tags', + 'key' => 'tags', 'size' => 255, 'required' => false, 'array' => true, @@ -5848,8 +5846,7 @@ trait TransactionsBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'columnId' => $col['columnId'], - 'name' => $col['name'], + 'key' => $col['columnId'], 'size' => 255, 'required' => false, 'array' => true, From ab5aac00c40a0fb2d41fa7821c4dbc669953eee5 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Tue, 11 Nov 2025 21:25:21 +1300 Subject: [PATCH 104/167] Format --- .../Platform/Modules/Databases/Http/Databases/Action.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php index f751fbab33..728e732cc5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php @@ -87,8 +87,7 @@ class Action extends AppwriteAction } catch (\Exception $e) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid operator for attribute "' . $key . '": ' . $e->getMessage()); } - } - elseif (\is_array($value)) { + } elseif (\is_array($value)) { $data[$key] = $this->parseOperators($value, $collection); } } From b28e53696766487a3c0b079801a3d3ef433671d8 Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 10:35:39 +0200 Subject: [PATCH 105/167] Add try catch --- app/controllers/api/account.php | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 41d746e7dc..11824ec066 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1725,14 +1725,15 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') try { $emailCanonical = new EmailCanonical($user->getAttribute('email')); - - $user->setAttribute('emailCanonical', $emailCanonical->getCanonical()); - $user->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()); - $user->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()); - $user->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()); - $user->setAttribute('emailIsFree', $emailCanonical->isFree()); } catch (Throwable) { + $emailCanonical = null; } + + $user->setAttribute('emailCanonical', $emailCanonical?->getCanonical()); + $user->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()); + $user->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()); + $user->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()); + $user->setAttribute('emailIsFree', $emailCanonical?->isFree()); } if (empty($user->getAttribute('name'))) { @@ -3136,16 +3137,20 @@ App::patch('/v1/account/email') throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */ } - $emailCanonical = new EmailCanonical($email); + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again - ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) - ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) - ->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()) - ->setAttribute('emailIsFree', $emailCanonical->isFree()) + ->setAttribute('emailCanonical', $emailCanonical?->getCanonical()) + ->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()) + ->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()) + ->setAttribute('emailIsFree', $emailCanonical?->isFree()) ; if (empty($passwordUpdate)) { From cc97d78b5a0eeb12d625f399f08116f2e755e016 Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 11:35:18 +0200 Subject: [PATCH 106/167] Add try catch --- app/controllers/api/users.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index f32d394d48..0efb355d46 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -99,7 +99,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e } try { - $emailCanonical = new EmailCanonical($email ?? ''); + $emailCanonical = new EmailCanonical($email); } catch (Throwable) { $emailCanonical = null; } From 27d0c511acea05096a0702dce9373a2b4af2ac7a Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 12:09:40 +0200 Subject: [PATCH 107/167] patch users email --- app/controllers/api/users.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 0efb355d46..db08709054 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1449,9 +1449,20 @@ App::patch('/v1/users/:userId/email') $oldEmail = $user->getAttribute('email'); + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) + ->setAttribute('emailCanonical', $emailCanonical?->getCanonical()) + ->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()) + ->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()) + ->setAttribute('emailIsFree', $emailCanonical?->isFree()) ; try { From da0a6b167fc376a0aa8bbd475d3d5be0e9872bbe Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 15:00:09 +0200 Subject: [PATCH 108/167] EmailValidator --- app/controllers/api/account.php | 86 ++++++++++++++++----------------- app/controllers/api/teams.php | 16 +++--- app/controllers/api/users.php | 30 ++++++------ 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 11824ec066..258479b10c 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -57,7 +57,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; -use Utopia\Emails\Email as EmailCanonical; +use Utopia\Emails\Email as EmailValidator; use Utopia\Locale\Locale; use Utopia\Storage\Validator\FileName; use Utopia\System\System; @@ -397,9 +397,9 @@ App::post('/v1/account') $password = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } try { @@ -430,11 +430,11 @@ App::post('/v1/account') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), + 'emailCanonical' => $emailValidator?->getCanonical(), + 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), + 'emailIsCorporate' => $emailValidator?->isCorporate(), + 'emailIsDisposable' => $emailValidator?->isDisposable(), + 'emailIsFree' => $emailValidator?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -1613,9 +1613,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } try { @@ -1645,11 +1645,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), + 'emailCanonical' => $emailValidator?->getCanonical(), + 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), + 'emailIsCorporate' => $emailValidator?->isCorporate(), + 'emailIsDisposable' => $emailValidator?->isDisposable(), + 'emailIsFree' => $emailValidator?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -1724,16 +1724,16 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $user->setAttribute('email', $oauth2->getUserEmail($accessToken)); try { - $emailCanonical = new EmailCanonical($user->getAttribute('email')); + $emailValidator = new EmailValidator($user->getAttribute('email')); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } - $user->setAttribute('emailCanonical', $emailCanonical?->getCanonical()); - $user->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()); - $user->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()); - $user->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()); - $user->setAttribute('emailIsFree', $emailCanonical?->isFree()); + $user->setAttribute('emailCanonical', $emailValidator?->getCanonical()); + $user->setAttribute('emailIsCanonical', $emailValidator?->isCanonicalSupported()); + $user->setAttribute('emailIsCorporate', $emailValidator?->isCorporate()); + $user->setAttribute('emailIsDisposable', $emailValidator?->isDisposable()); + $user->setAttribute('emailIsFree', $emailValidator?->isFree()); } if (empty($user->getAttribute('name'))) { @@ -2029,9 +2029,9 @@ App::post('/v1/account/tokens/magic-url') $userId = $userId === 'unique()' ? ID::unique() : $userId; try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } $user->setAttributes([ @@ -2058,11 +2058,11 @@ App::post('/v1/account/tokens/magic-url') 'authenticators' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), + 'emailCanonical' => $emailValidator?->getCanonical(), + 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), + 'emailIsCorporate' => $emailValidator?->isCorporate(), + 'emailIsDisposable' => $emailValidator?->isDisposable(), + 'emailIsFree' => $emailValidator?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -2290,9 +2290,9 @@ App::post('/v1/account/tokens/email') $userId = $userId === 'unique()' ? ID::unique() : $userId; try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } $user->setAttributes([ @@ -2317,11 +2317,11 @@ App::post('/v1/account/tokens/email') 'memberships' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), + 'emailCanonical' => $emailValidator?->getCanonical(), + 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), + 'emailIsCorporate' => $emailValidator?->isCorporate(), + 'emailIsDisposable' => $emailValidator?->isDisposable(), + 'emailIsFree' => $emailValidator?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -3138,19 +3138,19 @@ App::patch('/v1/account/email') } try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again - ->setAttribute('emailCanonical', $emailCanonical?->getCanonical()) - ->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()) - ->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()) - ->setAttribute('emailIsFree', $emailCanonical?->isFree()) + ->setAttribute('emailCanonical', $emailValidator?->getCanonical()) + ->setAttribute('emailIsCanonical', $emailValidator?->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailValidator?->isCorporate()) + ->setAttribute('emailIsDisposable', $emailValidator?->isDisposable()) + ->setAttribute('emailIsFree', $emailValidator?->isFree()) ; if (empty($passwordUpdate)) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index cbf1be4052..85120abe29 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -48,7 +48,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; -use Utopia\Emails\Email as EmailCanonical; +use Utopia\Emails\Email as EmailValidator; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -568,9 +568,9 @@ App::post('/v1/teams/:teamId/memberships') } try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } $userId = ID::unique(); @@ -605,11 +605,11 @@ App::post('/v1/teams/:teamId/memberships') 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $name]), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), + 'emailCanonical' => $emailValidator?->getCanonical(), + 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), + 'emailIsCorporate' => $emailValidator?->isCorporate(), + 'emailIsDisposable' => $emailValidator?->isDisposable(), + 'emailIsFree' => $emailValidator?->isFree(), ]); try { diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index db08709054..75504e581b 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -49,7 +49,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; -use Utopia\Emails\Email as EmailCanonical; +use Utopia\Emails\Email as EmailValidator; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -99,9 +99,9 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e } try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } $password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; @@ -131,11 +131,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $phone, $name]), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), + 'emailCanonical' => $emailValidator?->getCanonical(), + 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), + 'emailIsCorporate' => $emailValidator?->isCorporate(), + 'emailIsDisposable' => $emailValidator?->isDisposable(), + 'emailIsFree' => $emailValidator?->isFree(), ]); if ($hash === 'plaintext') { @@ -1450,19 +1450,19 @@ App::patch('/v1/users/:userId/email') $oldEmail = $user->getAttribute('email'); try { - $emailCanonical = new EmailCanonical($email); + $emailValidator = new EmailValidator($email); } catch (Throwable) { - $emailCanonical = null; + $emailValidator = null; } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) - ->setAttribute('emailCanonical', $emailCanonical?->getCanonical()) - ->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()) - ->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()) - ->setAttribute('emailIsFree', $emailCanonical?->isFree()) + ->setAttribute('emailCanonical', $emailValidator?->getCanonical()) + ->setAttribute('emailIsCanonical', $emailValidator?->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailValidator?->isCorporate()) + ->setAttribute('emailIsDisposable', $emailValidator?->isDisposable()) + ->setAttribute('emailIsFree', $emailValidator?->isFree()) ; try { From 8b4a56cd9b829c9bb7c0e07fbe6736570f569126 Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 15:25:10 +0200 Subject: [PATCH 109/167] $emailCanonical --- app/controllers/api/account.php | 100 ++++++++++++++++---------------- app/controllers/api/teams.php | 20 +++---- app/controllers/api/users.php | 54 ++++++++--------- 3 files changed, 87 insertions(+), 87 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 258479b10c..b7959bb6a9 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -20,7 +20,7 @@ use Appwrite\Event\Messaging; use Appwrite\Event\StatsUsage; use Appwrite\Extend\Exception; use Appwrite\Hooks\Hooks; -use Appwrite\Network\Validator\Email; +use Appwrite\Network\Validator\Email as EmailValidator; use Appwrite\Network\Validator\Redirect; use Appwrite\OpenSSL\OpenSSL; use Appwrite\SDK\AuthType; @@ -57,7 +57,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; -use Utopia\Emails\Email as EmailValidator; +use Utopia\Emails\Email; use Utopia\Locale\Locale; use Utopia\Storage\Validator\FileName; use Utopia\System\System; @@ -338,7 +338,7 @@ App::post('/v1/account') )) ->label('abuse-limit', 10) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be between 8 and 256 chars.', false, ['project', 'passwordsDictionary']) ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('request') @@ -397,9 +397,9 @@ App::post('/v1/account') $password = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } try { @@ -430,11 +430,11 @@ App::post('/v1/account') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailValidator?->getCanonical(), - 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), - 'emailIsCorporate' => $emailValidator?->isCorporate(), - 'emailIsDisposable' => $emailValidator?->isDisposable(), - 'emailIsFree' => $emailValidator?->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -917,7 +917,7 @@ App::post('/v1/account/sessions/email') )) ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},email:{param-email}') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password. Must be at least 8 chars.') ->inject('request') ->inject('response') @@ -1613,9 +1613,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } try { @@ -1645,11 +1645,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailValidator?->getCanonical(), - 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), - 'emailIsCorporate' => $emailValidator?->isCorporate(), - 'emailIsDisposable' => $emailValidator?->isDisposable(), - 'emailIsFree' => $emailValidator?->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -1724,16 +1724,16 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $user->setAttribute('email', $oauth2->getUserEmail($accessToken)); try { - $emailValidator = new EmailValidator($user->getAttribute('email')); + $emailCanonical = new Email($user->getAttribute('email')); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } - $user->setAttribute('emailCanonical', $emailValidator?->getCanonical()); - $user->setAttribute('emailIsCanonical', $emailValidator?->isCanonicalSupported()); - $user->setAttribute('emailIsCorporate', $emailValidator?->isCorporate()); - $user->setAttribute('emailIsDisposable', $emailValidator?->isDisposable()); - $user->setAttribute('emailIsFree', $emailValidator?->isFree()); + $user->setAttribute('emailCanonical', $emailCanonical?->getCanonical()); + $user->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()); + $user->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()); + $user->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()); + $user->setAttribute('emailIsFree', $emailCanonical?->isFree()); } if (empty($user->getAttribute('name'))) { @@ -1982,7 +1982,7 @@ App::post('/v1/account/tokens/magic-url') ->label('abuse-limit', 60) ->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}']) ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey']) ->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true) ->inject('request') @@ -2029,9 +2029,9 @@ App::post('/v1/account/tokens/magic-url') $userId = $userId === 'unique()' ? ID::unique() : $userId; try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } $user->setAttributes([ @@ -2058,11 +2058,11 @@ App::post('/v1/account/tokens/magic-url') 'authenticators' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailValidator?->getCanonical(), - 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), - 'emailIsCorporate' => $emailValidator?->isCorporate(), - 'emailIsDisposable' => $emailValidator?->isDisposable(), - 'emailIsFree' => $emailValidator?->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -2246,7 +2246,7 @@ App::post('/v1/account/tokens/email') ->label('abuse-limit', 10) ->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}']) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true) ->inject('request') ->inject('response') @@ -2290,9 +2290,9 @@ App::post('/v1/account/tokens/email') $userId = $userId === 'unique()' ? ID::unique() : $userId; try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } $user->setAttributes([ @@ -2317,11 +2317,11 @@ App::post('/v1/account/tokens/email') 'memberships' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailValidator?->getCanonical(), - 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), - 'emailIsCorporate' => $emailValidator?->isCorporate(), - 'emailIsDisposable' => $emailValidator?->isDisposable(), - 'emailIsFree' => $emailValidator?->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); $user->removeAttribute('$sequence'); @@ -3102,7 +3102,7 @@ App::patch('/v1/account/email') ], contentType: ContentType::JSON )) - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password. Must be at least 8 chars.') ->inject('requestTimestamp') ->inject('response') @@ -3138,19 +3138,19 @@ App::patch('/v1/account/email') } try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again - ->setAttribute('emailCanonical', $emailValidator?->getCanonical()) - ->setAttribute('emailIsCanonical', $emailValidator?->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailValidator?->isCorporate()) - ->setAttribute('emailIsDisposable', $emailValidator?->isDisposable()) - ->setAttribute('emailIsFree', $emailValidator?->isFree()) + ->setAttribute('emailCanonical', $emailCanonical?->getCanonical()) + ->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()) + ->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()) + ->setAttribute('emailIsFree', $emailCanonical?->isFree()) ; if (empty($passwordUpdate)) { @@ -3387,7 +3387,7 @@ App::post('/v1/account/recovery') )) ->label('abuse-limit', 10) ->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}']) - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['platforms', 'devKey']) ->inject('request') ->inject('response') diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 85120abe29..554ef6f4fe 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -10,7 +10,7 @@ use Appwrite\Event\Mail; use Appwrite\Event\Messaging; use Appwrite\Event\StatsUsage; use Appwrite\Extend\Exception; -use Appwrite\Network\Validator\Email; +use Appwrite\Network\Validator\Email as EmailValidator; use Appwrite\Network\Validator\Redirect; use Appwrite\Platform\Workers\Deletes; use Appwrite\SDK\AuthType; @@ -48,7 +48,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; -use Utopia\Emails\Email as EmailValidator; +use Utopia\Emails\Email; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -469,7 +469,7 @@ App::post('/v1/teams/:teamId/memberships') )) ->label('abuse-limit', 10) ->param('teamId', '', new UID(), 'Team ID.') - ->param('email', '', new Email(), 'Email of the new team member.', true) + ->param('email', '', new EmailValidator(), 'Email of the new team member.', true) ->param('userId', '', new UID(), 'ID of the user to be added to a team.', true) ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('roles', [], function (Document $project) { @@ -568,9 +568,9 @@ App::post('/v1/teams/:teamId/memberships') } try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } $userId = ID::unique(); @@ -605,11 +605,11 @@ App::post('/v1/teams/:teamId/memberships') 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $name]), - 'emailCanonical' => $emailValidator?->getCanonical(), - 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), - 'emailIsCorporate' => $emailValidator?->isCorporate(), - 'emailIsDisposable' => $emailValidator?->isDisposable(), - 'emailIsFree' => $emailValidator?->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); try { diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 75504e581b..956c9da042 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -16,7 +16,7 @@ use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Extend\Exception; use Appwrite\Hooks\Hooks; -use Appwrite\Network\Validator\Email; +use Appwrite\Network\Validator\Email as EmailValidator; use Appwrite\SDK\AuthType; use Appwrite\SDK\ContentType; use Appwrite\SDK\Deprecated; @@ -49,7 +49,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; -use Utopia\Emails\Email as EmailValidator; +use Utopia\Emails\Email; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -99,9 +99,9 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e } try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } $password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; @@ -131,11 +131,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $phone, $name]), - 'emailCanonical' => $emailValidator?->getCanonical(), - 'emailIsCanonical' => $emailValidator?->isCanonicalSupported(), - 'emailIsCorporate' => $emailValidator?->isCorporate(), - 'emailIsDisposable' => $emailValidator?->isDisposable(), - 'emailIsFree' => $emailValidator?->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), ]); if ($hash === 'plaintext') { @@ -220,7 +220,7 @@ App::post('/v1/users') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', null, new Email(), 'User email.', true) + ->param('email', null, new EmailValidator(), 'User email.', true) ->param('phone', null, new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'Plain text user password. Must be at least 8 chars.', true, ['project', 'passwordsDictionary']) ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) @@ -255,7 +255,7 @@ App::post('/v1/users/bcrypt') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using Bcrypt.') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') @@ -290,7 +290,7 @@ App::post('/v1/users/md5') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using MD5.') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') @@ -325,7 +325,7 @@ App::post('/v1/users/argon2') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using Argon2.') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') @@ -360,7 +360,7 @@ App::post('/v1/users/sha') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using SHA.') ->param('passwordVersion', '', new WhiteList(['sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']), "Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'", true) ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) @@ -402,7 +402,7 @@ App::post('/v1/users/phpass') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using PHPass.') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') @@ -437,7 +437,7 @@ App::post('/v1/users/scrypt') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using Scrypt.') ->param('passwordSalt', '', new Text(128), 'Optional salt used to hash password.') ->param('passwordCpu', 8, new Integer(), 'Optional CPU cost used to hash password.') @@ -485,7 +485,7 @@ App::post('/v1/users/scrypt-modified') ] )) ->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') + ->param('email', '', new EmailValidator(), 'User email.') ->param('password', '', new Password(), 'User password hashed using Scrypt Modified.') ->param('passwordSalt', '', new Text(128), 'Salt used to hash password.') ->param('passwordSaltSeparator', '', new Text(128), 'Salt separator used to hash password.') @@ -539,7 +539,7 @@ App::post('/v1/users/:userId/targets') switch ($providerType) { case 'email': - $validator = new Email(); + $validator = new EmailValidator(); if (!$validator->isValid($identifier)) { throw new Exception(Exception::GENERAL_INVALID_EMAIL); } @@ -1414,7 +1414,7 @@ App::patch('/v1/users/:userId/email') ] )) ->param('userId', '', new UID(), 'User ID.') - ->param('email', '', new Email(allowEmpty: true), 'User email.') + ->param('email', '', new EmailValidator(allowEmpty: true), 'User email.') ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') @@ -1450,19 +1450,19 @@ App::patch('/v1/users/:userId/email') $oldEmail = $user->getAttribute('email'); try { - $emailValidator = new EmailValidator($email); + $emailCanonical = new EmailValidator($email); } catch (Throwable) { - $emailValidator = null; + $emailCanonical = null; } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) - ->setAttribute('emailCanonical', $emailValidator?->getCanonical()) - ->setAttribute('emailIsCanonical', $emailValidator?->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailValidator?->isCorporate()) - ->setAttribute('emailIsDisposable', $emailValidator?->isDisposable()) - ->setAttribute('emailIsFree', $emailValidator?->isFree()) + ->setAttribute('emailCanonical', $emailCanonical?->getCanonical()) + ->setAttribute('emailIsCanonical', $emailCanonical?->isCanonicalSupported()) + ->setAttribute('emailIsCorporate', $emailCanonical?->isCorporate()) + ->setAttribute('emailIsDisposable', $emailCanonical?->isDisposable()) + ->setAttribute('emailIsFree', $emailCanonical?->isFree()) ; try { @@ -1723,7 +1723,7 @@ App::patch('/v1/users/:userId/targets/:targetId') switch ($providerType) { case 'email': - $validator = new Email(); + $validator = new EmailValidator(); if (!$validator->isValid($identifier)) { throw new Exception(Exception::GENERAL_INVALID_EMAIL); } From 97454c076887bb183a40277c89a067a44e4c089b Mon Sep 17 00:00:00 2001 From: fogelito <fogelshmuel@gmail.com> Date: Tue, 11 Nov 2025 15:33:16 +0200 Subject: [PATCH 110/167] EmailValidator chnage to email --- app/controllers/api/users.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 956c9da042..a3ef4f852b 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1450,7 +1450,7 @@ App::patch('/v1/users/:userId/email') $oldEmail = $user->getAttribute('email'); try { - $emailCanonical = new EmailValidator($email); + $emailCanonical = new Email($email); } catch (Throwable) { $emailCanonical = null; } From e01ac65ce81072b4ae42183ed0da063af4eb5970 Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 00:26:27 +0000 Subject: [PATCH 111/167] Feat: upgrade runtime --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index fe245d7837..753162cc89 100644 --- a/composer.lock +++ b/composer.lock @@ -161,16 +161,16 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.19.1", + "version": "0.19.2", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae" + "reference": "e5c142519df5aced37de9c302971c29c079ce3d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/runtimes/zipball/7bd0cc3cb97de625d7b07230bd91b121f88e72ae", - "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae", + "url": "https://api.github.com/repos/appwrite/runtimes/zipball/e5c142519df5aced37de9c302971c29c079ce3d9", + "reference": "e5c142519df5aced37de9c302971c29c079ce3d9", "shasum": "" }, "require": { @@ -210,9 +210,9 @@ ], "support": { "issues": "https://github.com/appwrite/runtimes/issues", - "source": "https://github.com/appwrite/runtimes/tree/0.19.1" + "source": "https://github.com/appwrite/runtimes/tree/0.19.2" }, - "time": "2025-05-27T07:12:56+00:00" + "time": "2025-11-11T13:44:44+00:00" }, { "name": "beberlei/assert", From eae26d90af72481a5137c5bbe537192ef250c1cc Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 09:25:35 +0545 Subject: [PATCH 112/167] Feat: enable Flutter 3.35 for sites --- app/config/template-runtimes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/template-runtimes.php b/app/config/template-runtimes.php index d1bb1a5b6a..1ad125d3d3 100644 --- a/app/config/template-runtimes.php +++ b/app/config/template-runtimes.php @@ -38,6 +38,6 @@ return [ ], 'FLUTTER' => [ 'name' => 'flutter', - 'versions' => ['3.32', '3.24'] + 'versions' => ['3.32', '3.24', '3.35'] ], ]; From 279682941a665e6500a26f5a3baa56cfd77e7cc2 Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 09:31:04 +0545 Subject: [PATCH 113/167] enable dart --- app/config/template-runtimes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/template-runtimes.php b/app/config/template-runtimes.php index 1ad125d3d3..2b2882cf10 100644 --- a/app/config/template-runtimes.php +++ b/app/config/template-runtimes.php @@ -14,7 +14,7 @@ return [ ], 'DART' => [ 'name' => 'dart', - 'versions' => ['3.8', '3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16'] + 'versions' => ['3.9', '3.8', '3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16'] ], 'GO' => [ 'name' => 'go', From cfd62cf0a1cedd66a20fc7c1ee441905f8443756 Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 09:32:12 +0545 Subject: [PATCH 114/167] Update template-runtimes.php --- app/config/template-runtimes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/template-runtimes.php b/app/config/template-runtimes.php index 2b2882cf10..04eaba2c44 100644 --- a/app/config/template-runtimes.php +++ b/app/config/template-runtimes.php @@ -38,6 +38,6 @@ return [ ], 'FLUTTER' => [ 'name' => 'flutter', - 'versions' => ['3.32', '3.24', '3.35'] + 'versions' => ['3.35', '3.32', '3.24'] ], ]; From ae21fadf0d5cd484dec9261f3c703d41aa98d731 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 12 Nov 2025 16:48:26 +1300 Subject: [PATCH 115/167] Fix event firing on txn ops --- .../Databases/Collections/Documents/Attribute/Decrement.php | 2 ++ .../Databases/Collections/Documents/Attribute/Increment.php | 2 ++ .../Http/Databases/Collections/Documents/Bulk/Delete.php | 2 ++ .../Http/Databases/Collections/Documents/Bulk/Update.php | 2 ++ .../Http/Databases/Collections/Documents/Bulk/Upsert.php | 2 ++ .../Databases/Http/Databases/Collections/Documents/Create.php | 2 ++ .../Databases/Http/Databases/Collections/Documents/Delete.php | 2 ++ .../Databases/Http/Databases/Collections/Documents/Update.php | 4 +++- .../Databases/Http/Databases/Collections/Documents/Upsert.php | 2 ++ 9 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php index 0b3d0e9fb4..4c6e1a38e3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php @@ -152,6 +152,8 @@ class Decrement extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually decrementing $groupId = $this->getGroupId(); $mockDocument = new Document([ diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php index ef64099fa8..56c76137db 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php @@ -152,6 +152,8 @@ class Increment extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually incrementing $groupId = $this->getGroupId(); $mockDocument = new Document([ diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php index 4b1251e016..d4c70d82bc 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php @@ -150,6 +150,8 @@ class Delete extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually deleting documents $response->dynamic(new Document([ $this->getSDKGroup() => [], diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php index 2152534efe..7b7e40567a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php @@ -174,6 +174,8 @@ class Update extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually updating documents $response->dynamic(new Document([ $this->getSDKGroup() => [], diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php index 6c869723a7..6ceec3b8f7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php @@ -149,6 +149,8 @@ class Upsert extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually upserting documents $response->dynamic(new Document([ $this->getSDKGroup() => [], diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index 521190d3dc..b80c170791 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -412,6 +412,8 @@ class Create extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually creating documents if ($isBulk) { $response->dynamic(new Document([ diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index a4cef59e5f..b9f3f7eb86 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -176,6 +176,8 @@ class Delete extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually deleting document $response->noContent(); return; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index ed83f3fdd3..060a60d863 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -243,7 +243,6 @@ class Update extends Action ->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, max($operations, 1)) ->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations); - // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) @@ -302,6 +301,9 @@ class Update extends Action ...$document->getArrayCopy(), ...$data ]); + + $queueForEvents->reset(); + $response ->setStatusCode(SwooleResponse::STATUS_CODE_OK) ->dynamic($mockDocument, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 8d47410649..96a4b32584 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -302,6 +302,8 @@ class Upsert extends Action ); }); + $queueForEvents->reset(); + // Return successful response without actually upserting document $groupId = $this->getGroupId(); $mockDocument = new Document([ From c9582978ed209e52e1d075827f8b749fb3384a53 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 12 Nov 2025 16:48:42 +1300 Subject: [PATCH 116/167] Fix operator parsing on txn ops --- .../Http/Databases/Collections/Documents/Bulk/Update.php | 4 +++- .../Http/Databases/Collections/Documents/Bulk/Upsert.php | 4 +++- .../Databases/Http/Databases/Collections/Documents/Update.php | 4 +++- .../Databases/Http/Databases/Collections/Documents/Upsert.php | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php index 7b7e40567a..5143dabc83 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php @@ -107,7 +107,9 @@ class Update extends Action throw new Exception($this->getParentNotFoundException()); } - $data = $this->parseOperators($data, $collection); + if ($transactionId === null) { + $data = $this->parseOperators($data, $collection); + } $hasRelationships = \array_filter( $collection->getAttribute('attributes', []), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php index 6ceec3b8f7..00699bdfab 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php @@ -107,7 +107,9 @@ class Upsert extends Action } foreach ($documents as $key => $document) { - $document = $this->parseOperators($document, $collection); + if ($transactionId === null) { + $document = $this->parseOperators($document, $collection); + } $document = $this->removeReadonlyAttributes($document, privileged: true); $documents[$key] = new Document($document); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index 060a60d863..f920c73281 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -112,7 +112,9 @@ class Update extends Action throw new Exception($this->getParentNotFoundException()); } - $data = $this->parseOperators($data, $collection); + if ($transactionId === null) { + $data = $this->parseOperators($data, $collection); + } // Read permission should not be required for update /** @var Document $document */ diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 96a4b32584..1d1db9bece 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -118,7 +118,9 @@ class Upsert extends Action throw new Exception($this->getParentNotFoundException()); } - $data = $this->parseOperators($data, $collection); + if ($transactionId === null) { + $data = $this->parseOperators($data, $collection); + } $allowedPermissions = [ Database::PERMISSION_READ, From 37910a4c5c4d14c4d45e0c57b4eb332f498599ab Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 12 Nov 2025 16:59:50 +1300 Subject: [PATCH 117/167] Fix space --- app/controllers/api/account.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 0dee54ef29..b6e1ebcc61 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1112,7 +1112,7 @@ App::post('/v1/account/sessions/anonymous') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $authorization-> skip(fn () => $dbForProject->createDocument('users', $user)); + $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; From aacaadcce0b71791dfb9b0a1c8ac0dd0820e7d9e Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:17:15 +0545 Subject: [PATCH 118/167] Fix: add default fallback to Flutter framework --- app/config/frameworks.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/config/frameworks.php b/app/config/frameworks.php index 0ab4a8a7db..022db67efb 100644 --- a/app/config/frameworks.php +++ b/app/config/frameworks.php @@ -282,6 +282,7 @@ return [ 'installCommand' => 'flutter pub get', 'outputDirectory' => './build/web', 'startCommand' => 'bash helpers/server.sh', + 'fallbackFile' => 'index.html' ], ], ], From 79d733486c9af746de131ae32fac415f2659c904 Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:35:31 +0545 Subject: [PATCH 119/167] Update Flutter framework default build runtime version to 3.35 --- app/config/frameworks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/frameworks.php b/app/config/frameworks.php index 022db67efb..47e26ac91e 100644 --- a/app/config/frameworks.php +++ b/app/config/frameworks.php @@ -273,7 +273,7 @@ return [ 'key' => 'flutter', 'name' => 'Flutter', 'screenshotSleep' => 5000, - 'buildRuntime' => 'flutter-3.29', + 'buildRuntime' => 'flutter-3.35', 'runtimes' => getVersions($templateRuntimes['FLUTTER']['versions'], 'flutter'), 'adapters' => [ 'static' => [ From d90b4c2f1930e42855ca9c6e2e2df9eefaa541dc Mon Sep 17 00:00:00 2001 From: Damodar Lohani <lohanidamodar@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:43:34 +0545 Subject: [PATCH 120/167] update framework config --- app/config/templates/site.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/templates/site.php b/app/config/templates/site.php index f2396b66db..c8bb019123 100644 --- a/app/config/templates/site.php +++ b/app/config/templates/site.php @@ -84,7 +84,7 @@ const TEMPLATE_FRAMEWORKS = [ 'installCommand' => '', 'buildCommand' => 'flutter build web', 'outputDirectory' => './build/web', - 'buildRuntime' => 'flutter-3.29', + 'buildRuntime' => 'flutter-3.35', 'adapter' => 'static', 'fallbackFile' => '', ], From 46d785bbb8acdbb37b6953897cb92142f5660c24 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 12 Nov 2025 21:04:17 +1300 Subject: [PATCH 121/167] Fix tests --- .../TablesDB/Transactions/TransactionsBase.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php index cbdc7826a0..09f62d165d 100644 --- a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php +++ b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php @@ -5589,6 +5589,12 @@ trait TransactionsBase ]), [ 'tableId' => ID::unique(), 'name' => 'Items', + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], ]); $this->assertEquals(201, $table['headers']['status-code']); @@ -5707,6 +5713,12 @@ trait TransactionsBase ]), [ 'tableId' => ID::unique(), 'name' => 'Tags', + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], ]); $this->assertEquals(201, $table['headers']['status-code']); @@ -5828,6 +5840,12 @@ trait TransactionsBase ]), [ 'tableId' => ID::unique(), 'name' => 'Arrays', + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], ]); $this->assertEquals(201, $table['headers']['status-code']); From 37f16ef0bb6500ab5c69f617329b19c58d8df319 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 12 Nov 2025 21:54:37 +1300 Subject: [PATCH 122/167] Fix array conversion --- .../Databases/Http/Databases/Transactions/Update.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index 07c2f17426..899c2b3eaf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -160,6 +160,10 @@ class Update extends Action $action = $operation['action']; $data = $operation['data']; + if ($data instanceof Document) { + $data = $data->getArrayCopy(); + } + if (!isset($collections[$collectionId])) { $collections[$collectionId] = Authorization::skip( fn () => $dbForProject->getCollection($collectionId) @@ -184,10 +188,6 @@ class Update extends Action $databaseOperations[$databaseInternalId] = ($databaseOperations[$databaseInternalId] ?? 0) + 1; } - if ($data instanceof Document) { - $data = $data->getArrayCopy(); - } - switch ($action) { case 'create': $this->handleCreateOperation($dbForProject, $collectionId, $documentId, $data, $createdAt, $state); From e8f2e78ac44a79536156b8c9ea08a8a53347d8b0 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 12 Nov 2025 22:18:25 +1300 Subject: [PATCH 123/167] Use internal bucket --- app/controllers/api/migrations.php | 8 +- .../examples/migrations/create-csv-export.md | 1 - .../examples/migrations/create-csv-export.md | 1 - .../migrations/migration-csv-export.md | 2 +- src/Appwrite/Platform/Workers/Migrations.php | 32 +++---- .../Services/Migrations/MigrationsBase.php | 83 +------------------ 6 files changed, 26 insertions(+), 101 deletions(-) diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 1d1e6e999c..41b98ab333 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -468,7 +468,6 @@ App::post('/v1/migrations/csv/exports') ] )) ->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database to export.') - ->param('bucketId', '', new UID(), 'Storage bucket unique ID where the exported CSV will be stored.') ->param('filename', '', new Text(255), 'The name of the file to be created for the export, excluding the .csv extension.') ->param('columns', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of attributes to export. If empty, all attributes will be exported. You can use the `*` wildcard to export all attributes from the collection.', true) ->param('queries', [], new ArrayList(new Text(0)), 'Array of query strings generated using the Query class provided by the SDK to filter documents to export. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) @@ -480,12 +479,12 @@ App::post('/v1/migrations/csv/exports') ->inject('user') ->inject('response') ->inject('dbForProject') + ->inject('dbForPlatform') ->inject('project') ->inject('queueForEvents') ->inject('queueForMigrations') ->action(function ( string $resourceId, - string $bucketId, string $filename, array $columns, array $queries, @@ -497,6 +496,7 @@ App::post('/v1/migrations/csv/exports') Document $user, Response $response, Database $dbForProject, + Database $dbForPlatform, Document $project, Event $queueForEvents, Migration $queueForMigrations @@ -507,7 +507,7 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); } - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'default')); if ($bucket->isEmpty()) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -553,7 +553,7 @@ App::post('/v1/migrations/csv/exports') 'resourceData' => '{}', 'errors' => [], 'options' => [ - 'bucketId' => $bucketId, + 'bucketId' => 'default', // Always use internal bucket 'filename' => $filename, 'columns' => $columns, 'queries' => $queries, diff --git a/docs/examples/1.8.x/console-cli/examples/migrations/create-csv-export.md b/docs/examples/1.8.x/console-cli/examples/migrations/create-csv-export.md index e56afae786..61eceabcd8 100644 --- a/docs/examples/1.8.x/console-cli/examples/migrations/create-csv-export.md +++ b/docs/examples/1.8.x/console-cli/examples/migrations/create-csv-export.md @@ -1,4 +1,3 @@ appwrite migrations create-csv-export \ --resource-id <ID1:ID2> \ - --bucket-id <BUCKET_ID> \ --filename <FILENAME> diff --git a/docs/examples/1.8.x/console-web/examples/migrations/create-csv-export.md b/docs/examples/1.8.x/console-web/examples/migrations/create-csv-export.md index e1b909a852..89f779fc4c 100644 --- a/docs/examples/1.8.x/console-web/examples/migrations/create-csv-export.md +++ b/docs/examples/1.8.x/console-web/examples/migrations/create-csv-export.md @@ -8,7 +8,6 @@ const migrations = new Migrations(client); const result = await migrations.createCSVExport({ resourceId: '<ID1:ID2>', - bucketId: '<BUCKET_ID>', filename: '<FILENAME>', columns: [], // optional queries: [], // optional diff --git a/docs/references/migrations/migration-csv-export.md b/docs/references/migrations/migration-csv-export.md index 866faed2d2..069dda895e 100644 --- a/docs/references/migrations/migration-csv-export.md +++ b/docs/references/migrations/migration-csv-export.md @@ -1 +1 @@ -Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in an Appwrite Storage bucket. \ No newline at end of file +Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete. \ No newline at end of file diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index fc7949e783..42d81d8999 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -16,6 +16,8 @@ use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; +use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Locale\Locale; use Utopia\Migration\Destination; @@ -432,13 +434,15 @@ class Migrations extends Action Mail $queueForMails ): void { $options = $migration->getAttribute('options', []); - $bucketId = $options['bucketId'] ?? null; + $bucketId = 'default'; // Always use platform default bucket $filename = $options['filename'] ?? 'export_' . \time(); $userInternalId = $options['userInternalId'] ?? ''; + $user = $this->dbForPlatform->findOne('users', [ + Query::equal('$sequence', [$userInternalId]) + ]); - $bucket = $this->dbForProject->getDocument('buckets', $bucketId); - if ($bucket->isEmpty()) { - throw new \Exception("Bucket not found: $bucketId"); + if ($user->isEmpty()) { + throw new \Exception('User ' . $userInternalId . ' not found'); } $path = $this->deviceForFiles->getPath($bucketId . '/' . $this->sanitizeFilename($filename) . '.csv'); @@ -469,7 +473,7 @@ class Migrations extends Action $this->sendCSVEmail( success: false, project: $project, - userInternalId: $userInternalId, + user: $user, options: $options, queueForMails: $queueForMails, sizeMB: $sizeMB @@ -479,9 +483,11 @@ class Migrations extends Action } } - $this->dbForProject->createDocument('bucket_' . $bucket->getSequence(), new Document([ + $this->dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), new Document([ '$id' => $fileId, - '$permissions' => [], + '$permissions' => [ + Permission::read(Role::user($user->getId())), + ], 'bucketId' => $bucket->getId(), 'bucketInternalId' => $bucket->getSequence(), 'name' => $filename, @@ -521,7 +527,7 @@ class Migrations extends Action $this->sendCSVEmail( success: true, project: $project, - userInternalId: $userInternalId, + user: $user, options: $options, queueForMails: $queueForMails, downloadUrl: $downloadUrl @@ -533,7 +539,7 @@ class Migrations extends Action * * @param bool $success Whether the export was successful * @param Document $project - * @param string $userInternalId Internal ID of the user + * @param string $user The user who triggered the operation * @param array $options Migration options * @param Mail $queueForMails * @param string $downloadUrl Download URL for successful exports @@ -544,7 +550,7 @@ class Migrations extends Action protected function sendCSVEmail( bool $success, Document $project, - string $userInternalId, + Document $user, array $options, Mail $queueForMails, string $downloadUrl = '', @@ -554,12 +560,8 @@ class Migrations extends Action return; } - $user = $this->dbForPlatform->findOne('users', [ - Query::equal('$sequence', [$userInternalId]) - ]); - if ($user->isEmpty()) { - Console::warning("User not found for CSV export notification: $userInternalId"); + Console::warning("User not found for CSV export notification: {$user->getInternalId()}"); return; } diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index 16e58c9c2c..a6ee9c15d5 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1282,39 +1282,11 @@ trait MigrationsBase $this->assertEquals(200, $docs['headers']['status-code']); $this->assertEquals(10, $docs['body']['total'], 'Expected 10 documents but got ' . $docs['body']['total']); - // Create a storage bucket for the export - $bucketIdUnique = ID::unique(); - $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'bucketId' => $bucketIdUnique, - 'name' => 'Test Export Bucket', - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'fileSecurity' => false, - 'enabled' => true, - 'maximumFileSize' => 10485760, // 10MB - 'allowedFileExtensions' => ['csv'], - 'compression' => 'none', - 'encryption' => false, - 'antivirus' => false - ]); - - $this->assertEquals(201, $bucket['headers']['status-code']); - $bucketId = $bucket['body']['$id']; - - // Perform CSV export with notification enabled + // Perform CSV export with notification enabled (uses internal bucket) $migration = $this->client->call(Client::METHOD_POST, '/migrations/csv/exports', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'bucketId' => $bucketId, 'resourceId' => $databaseId . ':' . $collectionId, 'filename' => 'test-export', 'columns' => [], @@ -1329,7 +1301,7 @@ trait MigrationsBase $this->assertNotEmpty($migration['body']['$id']); $migrationId = $migration['body']['$id']; - $this->assertEventually(function () use ($bucketId, $migrationId) { + $this->assertEventually(function () use ($migrationId) { $response = $this->client->call(Client::METHOD_GET, '/migrations/' . $migrationId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1341,55 +1313,10 @@ trait MigrationsBase $this->assertEquals('completed', $response['body']['status']); $this->assertEquals('Appwrite', $response['body']['source']); $this->assertEquals('CSV', $response['body']['destination']); - $this->assertEquals($bucketId, $response['body']['options']['bucketId']); return true; }, 30000, 500); - // Check that the file was created in the bucket - // Query files by filename - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'queries' => [ - Query::equal('name', ['test-export'])->toString() - ] - ]); - - $this->assertEquals(200, $files['headers']['status-code']); - $this->assertEquals(1, $files['body']['total'], 'Expected exactly one file with name "test-export"'); - - // Get the exported file - $file = $files['body']['files'][0]; - $fileId = $file['$id']; - - $this->assertEquals($bucketId, $file['bucketId']); - $this->assertEquals('test-export', $file['name']); - $this->assertEquals('text/csv', $file['mimeType']); - $this->assertGreaterThan(0, $file['sizeOriginal']); - - // Download and verify CSV content - $download = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', \array_merge([ - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $download['headers']['status-code']); - - $csvContent = $download['body']; - $lines = explode("\n", trim($csvContent)); - $this->assertCount(11, $lines); - $this->assertStringContainsString('$id', $lines[0]); - $this->assertStringContainsString('$permissions', $lines[0]); - $this->assertStringContainsString('$createdAt', $lines[0]); - $this->assertStringContainsString('$updatedAt', $lines[0]); - $this->assertStringContainsString('name', $lines[0]); - $this->assertStringContainsString('email', $lines[0]); - - $this->assertStringContainsString('Test User 1', $lines[1]); - $this->assertStringContainsString('user1@appwrite.io', $lines[1]); - // Check that email was sent with download link $lastEmail = $this->getLastEmail(); $this->assertNotEmpty($lastEmail); @@ -1407,6 +1334,8 @@ trait MigrationsBase \parse_str($components['query'] ?? '', $queryParams); $this->assertArrayHasKey('jwt', $queryParams, 'JWT not found in download URL'); $this->assertNotEmpty($queryParams['jwt']); + $this->assertArrayHasKey('project', $queryParams, 'Project not found in download URL'); + $this->assertStringContainsString('/storage/buckets/default/files/', $downloadUrl); // Test download with JWT $path = \str_replace('/v1', '', $components['path']); @@ -1426,9 +1355,5 @@ trait MigrationsBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]); - $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, [ - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]); } } From 08c9db7c60289a33f51c49351edcb85a70f346c8 Mon Sep 17 00:00:00 2001 From: Hemachandar <hmac.devo@gmail.com> Date: Wed, 12 Nov 2025 19:23:57 +0530 Subject: [PATCH 124/167] use inline validator --- .../Tokens/Http/Tokens/Buckets/Files/Create.php | 12 ++---------- .../Platform/Modules/Tokens/Http/Tokens/Update.php | 11 ++--------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index aa06753420..e4de4c1380 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -17,7 +17,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; -use Utopia\Validator\Text; +use Utopia\Validator\Nullable; class Create extends Action { @@ -61,7 +61,7 @@ class Create extends Action )) ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File unique ID.') - ->param('expire', null, new Text(100), 'Token expiry date', true) + ->param('expire', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Token expiry date', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') @@ -70,14 +70,6 @@ class Create extends Action public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents): void { - if (!is_null($expire)) { - $validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_DAYS, offset: 0); - if (!$validator->isValid($expire)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now'); - } - } - - /** * @var Document $bucket * @var Document $file diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php index b1b670532d..fef2c38a81 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Update.php @@ -14,7 +14,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; -use Utopia\Validator\Text; +use Utopia\Validator\Nullable; class Update extends Action { @@ -57,7 +57,7 @@ class Update extends Action contentType: ContentType::JSON )) ->param('tokenId', '', new UID(), 'Token unique ID.') - ->param('expire', null, new Text(100), 'File token expiry date', true) + ->param('expire', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'File token expiry date', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') @@ -66,13 +66,6 @@ class Update extends Action public function action(string $tokenId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents) { - if (!is_null($expire)) { - $validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_DAYS, offset: 0); - if (!$validator->isValid($expire)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now'); - } - } - $token = $dbForProject->getDocument('resourceTokens', $tokenId); if ($token->isEmpty()) { From bc19e667759720ea604d49ebac5b078f750531a4 Mon Sep 17 00:00:00 2001 From: Hemachandar <hmac.devo@gmail.com> Date: Wed, 12 Nov 2025 20:27:42 +0530 Subject: [PATCH 125/167] fix tests --- tests/e2e/Services/Tokens/TokensConsoleClientTest.php | 4 ++-- tests/e2e/Services/Tokens/TokensCustomServerTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/Services/Tokens/TokensConsoleClientTest.php b/tests/e2e/Services/Tokens/TokensConsoleClientTest.php index ab3790abca..f1480faba0 100644 --- a/tests/e2e/Services/Tokens/TokensConsoleClientTest.php +++ b/tests/e2e/Services/Tokens/TokensConsoleClientTest.php @@ -70,7 +70,7 @@ class TokensConsoleClientTest extends Scope 'expire' => '2022-11-02', ]); $this->assertEquals(400, $token['headers']['status-code']); - $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + $this->assertStringContainsString('Value must be valid date in the future', $token['body']['message']); // Success case: No expire date $token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ @@ -128,7 +128,7 @@ class TokensConsoleClientTest extends Scope 'expire' => '2022-11-02', ]); $this->assertEquals(400, $token['headers']['status-code']); - $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + $this->assertStringContainsString('Value must be valid date in the future', $token['body']['message']); // Finite expiry $expiry = date('Y-m-d', strtotime("tomorrow")); diff --git a/tests/e2e/Services/Tokens/TokensCustomServerTest.php b/tests/e2e/Services/Tokens/TokensCustomServerTest.php index eaf30049f9..779d5449b3 100644 --- a/tests/e2e/Services/Tokens/TokensCustomServerTest.php +++ b/tests/e2e/Services/Tokens/TokensCustomServerTest.php @@ -68,7 +68,7 @@ class TokensCustomServerTest extends Scope 'expire' => '2022-11-02', ]); $this->assertEquals(400, $token['headers']['status-code']); - $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + $this->assertStringContainsString('Value must be valid date in the future', $token['body']['message']); // Success case: No expire date $token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ @@ -102,7 +102,7 @@ class TokensCustomServerTest extends Scope 'expire' => '2022-11-02', ]); $this->assertEquals(400, $token['headers']['status-code']); - $this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']); + $this->assertStringContainsString('Value must be valid date in the future', $token['body']['message']); // Success case: Finite expiry $expiry = date('Y-m-d', strtotime("tomorrow")); From d411b741b32c810b02999ffc7a3c60833c49ab9f Mon Sep 17 00:00:00 2001 From: Atharva Deosthale <atharva.deosthale17@gmail.com> Date: Wed, 12 Nov 2025 23:06:18 +0530 Subject: [PATCH 126/167] address comments --- .../Modules/Functions/Http/Deployments/Template/Create.php | 3 ++- .../Modules/Sites/Http/Deployments/Template/Create.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php index 5e0266a09e..2f150dbe18 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php @@ -103,7 +103,8 @@ class Create extends Base throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$reference" : ""; + $branchUrl = "https://github.com/$owner/$repository/blob/$reference"; + $repositoryUrl = "https://github.com/$owner/$repository"; $template = new Document([ diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index d7196eb3d5..d55d09584d 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -105,7 +105,7 @@ class Create extends Base throw new Exception(Exception::SITE_NOT_FOUND); } - $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$reference" : ""; + $branchUrl = "https://github.com/$owner/$repository/blob/$reference"; $repositoryUrl = "https://github.com/$owner/$repository"; $template = new Document([ From 3a6d907b4207cf85ad98709857a893f24d0b15c3 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 13 Nov 2025 11:29:38 +0530 Subject: [PATCH 127/167] release flutter + dart and add screenshot api docs --- app/config/specs/open-api3-1.8.x-console.json | 16 +++-- app/config/specs/open-api3-1.8.x-server.json | 16 +++-- .../specs/open-api3-latest-console.json | 16 +++-- app/config/specs/open-api3-latest-server.json | 16 +++-- app/config/specs/swagger2-1.8.x-console.json | 16 +++-- app/config/specs/swagger2-1.8.x-server.json | 16 +++-- app/config/specs/swagger2-latest-console.json | 16 +++-- app/config/specs/swagger2-latest-server.json | 16 +++-- composer.lock | 36 +++++----- .../java/avatars/get-screenshot.md | 41 ++++++++++++ .../kotlin/avatars/get-screenshot.md | 32 +++++++++ .../examples/avatars/get-screenshot.md | 32 +++++++++ .../examples/avatars/get-screenshot.md | 65 +++++++++++++++++++ .../examples/avatars/get-screenshot.md | 0 .../examples/avatars/get-screenshot.md | 32 +++++++++ .../examples/avatars/get-screenshot.md | 6 ++ .../examples/avatars/get-screenshot.md | 32 +++++++++ .../examples/avatars/get-screenshot.md | 32 +++++++++ .../examples/avatars/get-screenshot.md | 31 +++++++++ .../examples/avatars/get-screenshot.md | 34 ++++++++++ .../examples/avatars/get-screenshot.md | 38 +++++++++++ .../examples/avatars/get-screenshot.md | 0 .../java/avatars/get-screenshot.md | 42 ++++++++++++ .../kotlin/avatars/get-screenshot.md | 33 ++++++++++ .../examples/avatars/get-screenshot.md | 31 +++++++++ .../examples/avatars/get-screenshot.md | 32 +++++++++ .../examples/avatars/get-screenshot.md | 7 ++ .../examples/avatars/get-screenshot.md | 33 ++++++++++ .../examples/avatars/get-screenshot.md | 33 ++++++++++ docs/sdks/dart/CHANGELOG.md | 5 ++ docs/sdks/flutter/CHANGELOG.md | 4 ++ 31 files changed, 709 insertions(+), 50 deletions(-) create mode 100644 docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-apple/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-graphql/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-rest/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-go/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-graphql/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-rest/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md create mode 100644 docs/examples/1.8.x/server-swift/examples/avatars/get-screenshot.md 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 aa1e81dbeb..287c33e5ec 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -13105,6 +13105,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13131,7 +13132,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -13746,6 +13748,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13772,7 +13775,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -30954,6 +30958,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -30980,7 +30985,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -31601,6 +31607,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -31627,7 +31634,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] 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 c3df6ef373..ff4af79c91 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -12127,6 +12127,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12153,7 +12154,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -12529,6 +12531,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12555,7 +12558,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -21703,6 +21707,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -21729,7 +21734,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -22122,6 +22128,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -22148,7 +22155,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index aa1e81dbeb..287c33e5ec 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -13105,6 +13105,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13131,7 +13132,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -13746,6 +13748,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13772,7 +13775,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -30954,6 +30958,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -30980,7 +30985,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -31601,6 +31607,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -31627,7 +31634,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index c3df6ef373..ff4af79c91 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -12127,6 +12127,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12153,7 +12154,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -12529,6 +12531,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12555,7 +12558,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -21703,6 +21707,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -21729,7 +21734,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -22122,6 +22128,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -22148,7 +22155,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 158b308f87..4562120363 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -13041,6 +13041,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13067,7 +13068,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -13683,6 +13685,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13709,7 +13712,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -31058,6 +31062,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -31084,7 +31089,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -31708,6 +31714,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -31734,7 +31741,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index 8b972be590..9603ed313f 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -12078,6 +12078,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12104,7 +12105,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -12493,6 +12495,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12519,7 +12522,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -21845,6 +21849,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -21871,7 +21876,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -22277,6 +22283,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -22303,7 +22310,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 158b308f87..4562120363 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -13041,6 +13041,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13067,7 +13068,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -13683,6 +13685,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -13709,7 +13712,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -31058,6 +31062,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -31084,7 +31089,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -31708,6 +31714,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -31734,7 +31741,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 8b972be590..9603ed313f 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -12078,6 +12078,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12104,7 +12105,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -12493,6 +12495,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -12519,7 +12522,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -21845,6 +21849,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -21871,7 +21876,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] @@ -22277,6 +22283,7 @@ "dart-3.3", "dart-3.5", "dart-3.8", + "dart-3.9", "dotnet-6.0", "dotnet-7.0", "dotnet-8.0", @@ -22303,7 +22310,8 @@ "flutter-3.24", "flutter-3.27", "flutter-3.29", - "flutter-3.32" + "flutter-3.32", + "flutter-3.35" ], "x-enum-name": null, "x-enum-keys": [] diff --git a/composer.lock b/composer.lock index 753162cc89..77216d6346 100644 --- a/composer.lock +++ b/composer.lock @@ -756,16 +756,16 @@ }, { "name": "google/protobuf", - "version": "v4.33.0", + "version": "v4.33.1", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d" + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/b50269e23204e5ae859a326ec3d90f09efe3047d", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/0cd73ccf0cd26c3e72299cce1ea6144091a57e12", + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12", "shasum": "" }, "require": { @@ -794,9 +794,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.0" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.1" }, - "time": "2025-10-15T20:10:28+00:00" + "time": "2025-11-12T21:58:05+00:00" }, { "name": "league/csv", @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.2.0", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" + "reference": "8062cfc42ce93c0b28c325fa632f6392e5d6c0d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", + "url": "https://api.github.com/repos/utopia-php/database/zipball/8062cfc42ce93c0b28c325fa632f6392e5d6c0d2", + "reference": "8062cfc42ce93c0b28c325fa632f6392e5d6c0d2", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.2.0" + "source": "https://github.com/utopia-php/database/tree/3.3.0" }, - "time": "2025-11-06T05:41:54+00:00" + "time": "2025-11-12T08:20:59+00:00" }, { "name": "utopia-php/detector", @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.3", + "version": "1.5.4", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" + "reference": "958947b6483a79e11c3812f23bb3056199fa4105" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/958947b6483a79e11c3812f23bb3056199fa4105", + "reference": "958947b6483a79e11c3812f23bb3056199fa4105", "shasum": "" }, "require": { @@ -5428,9 +5428,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.5.3" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.4" }, - "time": "2025-11-10T09:50:41+00:00" + "time": "2025-11-12T12:43:42+00:00" }, { "name": "doctrine/annotations", diff --git a/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md b/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md new file mode 100644 index 0000000000..077716f523 --- /dev/null +++ b/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md @@ -0,0 +1,41 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("<YOUR_PROJECT_ID>"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getScreenshot( + "https://example.com", // url + mapOf( "a" to "b" ), // headers (optional) + 1, // viewportWidth (optional) + 1, // viewportHeight (optional) + 0.1, // scale (optional) + theme.LIGHT, // theme (optional) + "<USER_AGENT>", // userAgent (optional) + false, // fullpage (optional) + "<LOCALE>", // locale (optional) + timezone.AFRICA_ABIDJAN, // timezone (optional) + -90, // latitude (optional) + -180, // longitude (optional) + 0, // accuracy (optional) + false, // touch (optional) + listOf(), // permissions (optional) + 0, // sleep (optional) + 0, // width (optional) + 0, // height (optional) + -1, // quality (optional) + output.JPG, // output (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); + diff --git a/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md b/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md new file mode 100644 index 0000000000..014ca90fd8 --- /dev/null +++ b/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md @@ -0,0 +1,32 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("<YOUR_PROJECT_ID>") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getScreenshot( + url = "https://example.com", + headers = mapOf( "a" to "b" ), // (optional) + viewportWidth = 1, // (optional) + viewportHeight = 1, // (optional) + scale = 0.1, // (optional) + theme = theme.LIGHT, // (optional) + userAgent = "<USER_AGENT>", // (optional) + fullpage = false, // (optional) + locale = "<LOCALE>", // (optional) + timezone = timezone.AFRICA_ABIDJAN, // (optional) + latitude = -90, // (optional) + longitude = -180, // (optional) + accuracy = 0, // (optional) + touch = false, // (optional) + permissions = listOf(), // (optional) + sleep = 0, // (optional) + width = 0, // (optional) + height = 0, // (optional) + quality = -1, // (optional) + output = output.JPG, // (optional) +) \ No newline at end of file diff --git a/docs/examples/1.8.x/client-apple/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-apple/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..7f4ef5da5c --- /dev/null +++ b/docs/examples/1.8.x/client-apple/examples/avatars/get-screenshot.md @@ -0,0 +1,32 @@ +import Appwrite +import AppwriteEnums + +let client = Client() + .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("<YOUR_PROJECT_ID>") // Your project ID + +let avatars = Avatars(client) + +let bytes = try await avatars.getScreenshot( + url: "https://example.com", + headers: [:], // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .light, // optional + userAgent: "<USER_AGENT>", // optional + fullpage: false, // optional + locale: "<LOCALE>", // optional + timezone: .africaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .jpg // optional +) + diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..768cb8f271 --- /dev/null +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md @@ -0,0 +1,65 @@ +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('<YOUR_PROJECT_ID>'); // Your project ID + +Avatars avatars = Avatars(client); + +// Downloading file +UInt8List bytes = await avatars.getScreenshot( + url: 'https://example.com', + headers: {}, // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .light, // optional + userAgent: '<USER_AGENT>', // optional + fullpage: false, // optional + locale: '<LOCALE>', // optional + timezone: .africaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .jpg, // optional +) + +final file = File('path_to_file/filename.ext'); +file.writeAsBytesSync(bytes); + +// Displaying image preview +FutureBuilder( + future: avatars.getScreenshot( + url:'https://example.com' , + headers:{} , // optional + viewportWidth:1 , // optional + viewportHeight:1 , // optional + scale:0.1 , // optional + theme: .light, // optional + userAgent:'<USER_AGENT>' , // optional + fullpage:false , // optional + locale:'<LOCALE>' , // optional + timezone: .africaAbidjan, // optional + latitude:-90 , // optional + longitude:-180 , // optional + accuracy:0 , // optional + touch:false , // optional + permissions:[] , // optional + sleep:0 , // optional + width:0 , // optional + height:0 , // optional + quality:-1 , // optional + output: .jpg, // optional +), // Works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory(snapshot.data) + : CircularProgressIndicator(); + } +); diff --git a/docs/examples/1.8.x/client-graphql/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-graphql/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..7482b4cf0e --- /dev/null +++ b/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md @@ -0,0 +1,32 @@ +import { Client, Avatars, , , } from "react-native-appwrite"; + +const client = new Client() + .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('<YOUR_PROJECT_ID>'); // Your project ID + +const avatars = new Avatars(client); + +const result = avatars.getScreenshot({ + url: 'https://example.com', + headers: {}, // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .Light, // optional + userAgent: '<USER_AGENT>', // optional + fullpage: false, // optional + locale: '<LOCALE>', // optional + timezone: .AfricaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .Jpg // optional +}); + +console.log(result); diff --git a/docs/examples/1.8.x/client-rest/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-rest/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..b4c31ca100 --- /dev/null +++ b/docs/examples/1.8.x/client-rest/examples/avatars/get-screenshot.md @@ -0,0 +1,6 @@ +GET /v1/avatars/screenshots HTTP/1.1 +Host: cloud.appwrite.io +X-Appwrite-Response-Format: 1.8.0 +X-Appwrite-Project: <YOUR_PROJECT_ID> +X-Appwrite-Session: +X-Appwrite-JWT: <YOUR_JWT> diff --git a/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..c4722be633 --- /dev/null +++ b/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md @@ -0,0 +1,32 @@ +import { Client, Avatars, , , } from "appwrite"; + +const client = new Client() + .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('<YOUR_PROJECT_ID>'); // Your project ID + +const avatars = new Avatars(client); + +const result = avatars.getScreenshot({ + url: 'https://example.com', + headers: {}, // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .Light, // optional + userAgent: '<USER_AGENT>', // optional + fullpage: false, // optional + locale: '<LOCALE>', // optional + timezone: .AfricaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .Jpg // optional +}); + +console.log(result); diff --git a/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..3a9437515d --- /dev/null +++ b/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md @@ -0,0 +1,32 @@ +import { Client, Avatars, , , } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('<YOUR_PROJECT_ID>'); // Your project ID + +const avatars = new Avatars(client); + +const result = avatars.getScreenshot({ + url: 'https://example.com', + headers: {}, // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .Light, // optional + userAgent: '<USER_AGENT>', // optional + fullpage: false, // optional + locale: '<LOCALE>', // optional + timezone: .AfricaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .Jpg // optional +}); + +console.log(result); diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..7630648f98 --- /dev/null +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md @@ -0,0 +1,31 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('<YOUR_PROJECT_ID>') // Your project ID + .setSession(''); // The user session to authenticate with + +Avatars avatars = Avatars(client); + +UInt8List result = await avatars.getScreenshot( + url: 'https://example.com', + headers: {}, // (optional) + viewportWidth: 1, // (optional) + viewportHeight: 1, // (optional) + scale: 0.1, // (optional) + theme: .light, // (optional) + userAgent: '<USER_AGENT>', // (optional) + fullpage: false, // (optional) + locale: '<LOCALE>', // (optional) + timezone: .africaAbidjan, // (optional) + latitude: -90, // (optional) + longitude: -180, // (optional) + accuracy: 0, // (optional) + touch: false, // (optional) + permissions: [], // (optional) + sleep: 0, // (optional) + width: 0, // (optional) + height: 0, // (optional) + quality: -1, // (optional) + output: .jpg, // (optional) +); diff --git a/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..f5c3542a97 --- /dev/null +++ b/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md @@ -0,0 +1,34 @@ +using Appwrite; +using Appwrite.Enums; +using Appwrite.Models; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("<YOUR_PROJECT_ID>") // Your project ID + .SetSession(""); // The user session to authenticate with + +Avatars avatars = new Avatars(client); + +byte[] result = await avatars.GetScreenshot( + url: "https://example.com", + headers: [object], // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .Light, // optional + userAgent: "<USER_AGENT>", // optional + fullpage: false, // optional + locale: "<LOCALE>", // optional + timezone: .AfricaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: new List<string>(), // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .Jpg // optional +); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-go/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-go/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..ac425fbc4f --- /dev/null +++ b/docs/examples/1.8.x/server-go/examples/avatars/get-screenshot.md @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/avatars" +) + +client := client.New( + client.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1") + client.WithProject("<YOUR_PROJECT_ID>") + client.WithSession("") +) + +service := avatars.New(client) + +response, error := service.GetScreenshot( + "https://example.com", + avatars.WithGetScreenshotHeaders(map[string]interface{}{}), + avatars.WithGetScreenshotViewportWidth(1), + avatars.WithGetScreenshotViewportHeight(1), + avatars.WithGetScreenshotScale(0.1), + avatars.WithGetScreenshotTheme("light"), + avatars.WithGetScreenshotUserAgent("<USER_AGENT>"), + avatars.WithGetScreenshotFullpage(false), + avatars.WithGetScreenshotLocale("<LOCALE>"), + avatars.WithGetScreenshotTimezone("africa/abidjan"), + avatars.WithGetScreenshotLatitude(-90), + avatars.WithGetScreenshotLongitude(-180), + avatars.WithGetScreenshotAccuracy(0), + avatars.WithGetScreenshotTouch(false), + avatars.WithGetScreenshotPermissions([]interface{}{}), + avatars.WithGetScreenshotSleep(0), + avatars.WithGetScreenshotWidth(0), + avatars.WithGetScreenshotHeight(0), + avatars.WithGetScreenshotQuality(-1), + avatars.WithGetScreenshotOutput("jpg"), +) diff --git a/docs/examples/1.8.x/server-graphql/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-graphql/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md b/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md new file mode 100644 index 0000000000..cf734af3b2 --- /dev/null +++ b/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md @@ -0,0 +1,42 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("<YOUR_PROJECT_ID>") // Your project ID + .setSession(""); // The user session to authenticate with + +Avatars avatars = new Avatars(client); + +avatars.getScreenshot( + "https://example.com", // url + mapOf( "a" to "b" ), // headers (optional) + 1, // viewportWidth (optional) + 1, // viewportHeight (optional) + 0.1, // scale (optional) + .LIGHT, // theme (optional) + "<USER_AGENT>", // userAgent (optional) + false, // fullpage (optional) + "<LOCALE>", // locale (optional) + .AFRICA_ABIDJAN, // timezone (optional) + -90, // latitude (optional) + -180, // longitude (optional) + 0, // accuracy (optional) + false, // touch (optional) + listOf(), // permissions (optional) + 0, // sleep (optional) + 0, // width (optional) + 0, // height (optional) + -1, // quality (optional) + .JPG, // output (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); + diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md b/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md new file mode 100644 index 0000000000..96032bb8a4 --- /dev/null +++ b/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md @@ -0,0 +1,33 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Avatars + +val client = Client() + .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("<YOUR_PROJECT_ID>") // Your project ID + .setSession("") // The user session to authenticate with + +val avatars = Avatars(client) + +val result = avatars.getScreenshot( + url = "https://example.com", + headers = mapOf( "a" to "b" ), // optional + viewportWidth = 1, // optional + viewportHeight = 1, // optional + scale = 0.1, // optional + theme = "light", // optional + userAgent = "<USER_AGENT>", // optional + fullpage = false, // optional + locale = "<LOCALE>", // optional + timezone = "africa/abidjan", // optional + latitude = -90, // optional + longitude = -180, // optional + accuracy = 0, // optional + touch = false, // optional + permissions = listOf(), // optional + sleep = 0, // optional + width = 0, // optional + height = 0, // optional + quality = -1, // optional + output = "jpg" // optional +) diff --git a/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..5f7b40cece --- /dev/null +++ b/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md @@ -0,0 +1,31 @@ +const sdk = require('node-appwrite'); + +const client = new sdk.Client() + .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('<YOUR_PROJECT_ID>') // Your project ID + .setSession(''); // The user session to authenticate with + +const avatars = new sdk.Avatars(client); + +const result = await avatars.getScreenshot({ + url: 'https://example.com', + headers: {}, // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: sdk..Light, // optional + userAgent: '<USER_AGENT>', // optional + fullpage: false, // optional + locale: '<LOCALE>', // optional + timezone: sdk..AfricaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: sdk..Jpg // optional +}); diff --git a/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..34bdf8ac7a --- /dev/null +++ b/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md @@ -0,0 +1,32 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with + +avatars = Avatars(client) + +result = avatars.get_screenshot( + url = 'https://example.com', + headers = {}, # optional + viewport_width = 1, # optional + viewport_height = 1, # optional + scale = 0.1, # optional + theme = .LIGHT, # optional + user_agent = '<USER_AGENT>', # optional + fullpage = False, # optional + locale = '<LOCALE>', # optional + timezone = .AFRICA_ABIDJAN, # optional + latitude = -90, # optional + longitude = -180, # optional + accuracy = 0, # optional + touch = False, # optional + permissions = [], # optional + sleep = 0, # optional + width = 0, # optional + height = 0, # optional + quality = -1, # optional + output = .JPG # optional +) diff --git a/docs/examples/1.8.x/server-rest/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-rest/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..0ab16b59e6 --- /dev/null +++ b/docs/examples/1.8.x/server-rest/examples/avatars/get-screenshot.md @@ -0,0 +1,7 @@ +GET /v1/avatars/screenshots HTTP/1.1 +Host: cloud.appwrite.io +X-Appwrite-Response-Format: 1.8.0 +X-Appwrite-Project: <YOUR_PROJECT_ID> +X-Appwrite-Session: +X-Appwrite-Key: <YOUR_API_KEY> +X-Appwrite-JWT: <YOUR_JWT> diff --git a/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..f2af537fe8 --- /dev/null +++ b/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md @@ -0,0 +1,33 @@ +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('<YOUR_PROJECT_ID>') # Your project ID + .set_session('') # The user session to authenticate with + +avatars = Avatars.new(client) + +result = avatars.get_screenshot( + url: 'https://example.com', + headers: {}, # optional + viewport_width: 1, # optional + viewport_height: 1, # optional + scale: 0.1, # optional + theme: ::LIGHT, # optional + user_agent: '<USER_AGENT>', # optional + fullpage: false, # optional + locale: '<LOCALE>', # optional + timezone: ::AFRICA_ABIDJAN, # optional + latitude: -90, # optional + longitude: -180, # optional + accuracy: 0, # optional + touch: false, # optional + permissions: [], # optional + sleep: 0, # optional + width: 0, # optional + height: 0, # optional + quality: -1, # optional + output: ::JPG # optional +) diff --git a/docs/examples/1.8.x/server-swift/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-swift/examples/avatars/get-screenshot.md new file mode 100644 index 0000000000..3aa1661093 --- /dev/null +++ b/docs/examples/1.8.x/server-swift/examples/avatars/get-screenshot.md @@ -0,0 +1,33 @@ +import Appwrite +import AppwriteEnums + +let client = Client() + .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("<YOUR_PROJECT_ID>") // Your project ID + .setSession("") // The user session to authenticate with + +let avatars = Avatars(client) + +let bytes = try await avatars.getScreenshot( + url: "https://example.com", + headers: [:], // optional + viewportWidth: 1, // optional + viewportHeight: 1, // optional + scale: 0.1, // optional + theme: .light, // optional + userAgent: "<USER_AGENT>", // optional + fullpage: false, // optional + locale: "<LOCALE>", // optional + timezone: .africaAbidjan, // optional + latitude: -90, // optional + longitude: -180, // optional + accuracy: 0, // optional + touch: false, // optional + permissions: [], // optional + sleep: 0, // optional + width: 0, // optional + height: 0, // optional + quality: -1, // optional + output: .jpg // optional +) + diff --git a/docs/sdks/dart/CHANGELOG.md b/docs/sdks/dart/CHANGELOG.md index 1a2cd6a5be..fdd7815cfc 100644 --- a/docs/sdks/dart/CHANGELOG.md +++ b/docs/sdks/dart/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 19.4.0 + +* Add `getScreenshot` method to `Avatars` service +* Fix passing of `null` values and stripping only non-nullable optional parameters from the request body + ## 19.3.0 * Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance diff --git a/docs/sdks/flutter/CHANGELOG.md b/docs/sdks/flutter/CHANGELOG.md index 5ab7d3269a..2f26f34edd 100644 --- a/docs/sdks/flutter/CHANGELOG.md +++ b/docs/sdks/flutter/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 20.3.1 + +* Fix passing of `null` values and stripping only non-nullable optional parameters from the request body + ## 20.3.0 * Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance From fcc07533e1a4caecbbfafec7355f263195fdddcb Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 13 Nov 2025 11:34:35 +0530 Subject: [PATCH 128/167] update changelog --- docs/sdks/dart/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sdks/dart/CHANGELOG.md b/docs/sdks/dart/CHANGELOG.md index fdd7815cfc..7fd7227f15 100644 --- a/docs/sdks/dart/CHANGELOG.md +++ b/docs/sdks/dart/CHANGELOG.md @@ -3,6 +3,8 @@ ## 19.4.0 * Add `getScreenshot` method to `Avatars` service +* Add enums `Theme`, `Output` and `Timezone` +* Update runtime enums to add support for `dart39` and `flutter335` runtimes * Fix passing of `null` values and stripping only non-nullable optional parameters from the request body ## 19.3.0 From b2991709dc9ef5c51cb71f27f20fe94f6993c35c Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 13 Nov 2025 11:38:50 +0530 Subject: [PATCH 129/167] update version --- app/config/platforms.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/platforms.php b/app/config/platforms.php index 5d72a8914c..2b5c107648 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -60,7 +60,7 @@ return [ [ 'key' => 'flutter', 'name' => 'Flutter', - 'version' => '20.3.0', + 'version' => '20.3.1', 'url' => 'https://github.com/appwrite/sdk-for-flutter', 'package' => 'https://pub.dev/packages/appwrite', 'enabled' => true, @@ -376,7 +376,7 @@ return [ [ 'key' => 'dart', 'name' => 'Dart', - 'version' => '19.3.0', + 'version' => '19.4.0', 'url' => 'https://github.com/appwrite/sdk-for-dart', 'package' => 'https://pub.dev/packages/dart_appwrite', 'enabled' => true, From c1b50e99411291fea3c55be43a3942a7d13a44a7 Mon Sep 17 00:00:00 2001 From: Damodar Lohani <dlohani48@gmail.com> Date: Thu, 13 Nov 2025 06:59:03 +0000 Subject: [PATCH 130/167] Upgrade utopia-php database --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 753162cc89..a91e4b1b03 100644 --- a/composer.lock +++ b/composer.lock @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.2.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", + "url": "https://api.github.com/repos/utopia-php/database/zipball/e10b4faa4f3a3ef30a5f6d76acdb605469924aec", + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.2.0" + "source": "https://github.com/utopia-php/database/tree/3.4.0" }, - "time": "2025-11-06T05:41:54+00:00" + "time": "2025-11-13T06:34:20+00:00" }, { "name": "utopia-php/detector", From 1da4736d5d2b3a299b43c97ea84ad18378dd05f1 Mon Sep 17 00:00:00 2001 From: shimon <shimon@appwrite.io> Date: Thu, 13 Nov 2025 11:23:26 +0200 Subject: [PATCH 131/167] composer.lock --- composer.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/composer.lock b/composer.lock index 64c5df8f51..8692e3e3de 100644 --- a/composer.lock +++ b/composer.lock @@ -756,16 +756,16 @@ }, { "name": "google/protobuf", - "version": "v4.33.0", + "version": "v4.33.1", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d" + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/b50269e23204e5ae859a326ec3d90f09efe3047d", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/0cd73ccf0cd26c3e72299cce1ea6144091a57e12", + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12", "shasum": "" }, "require": { @@ -794,9 +794,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.0" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.1" }, - "time": "2025-10-15T20:10:28+00:00" + "time": "2025-11-12T21:58:05+00:00" }, { "name": "league/csv", @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "4.1.0", + "version": "4.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "ce3986e82edc4968fe7eca152c0f5e0006059df9" + "reference": "3038eb6336dfef6da3f4d68178baa70d00cfc906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/ce3986e82edc4968fe7eca152c0f5e0006059df9", - "reference": "ce3986e82edc4968fe7eca152c0f5e0006059df9", + "url": "https://api.github.com/repos/utopia-php/database/zipball/3038eb6336dfef6da3f4d68178baa70d00cfc906", + "reference": "3038eb6336dfef6da3f4d68178baa70d00cfc906", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/4.1.0" + "source": "https://github.com/utopia-php/database/tree/4.2.0" }, - "time": "2025-11-12T03:43:25+00:00" + "time": "2025-11-12T09:03:35+00:00" }, { "name": "utopia-php/detector", @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.3", + "version": "1.5.4", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" + "reference": "958947b6483a79e11c3812f23bb3056199fa4105" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/958947b6483a79e11c3812f23bb3056199fa4105", + "reference": "958947b6483a79e11c3812f23bb3056199fa4105", "shasum": "" }, "require": { @@ -5428,9 +5428,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.5.3" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.4" }, - "time": "2025-11-10T09:50:41+00:00" + "time": "2025-11-12T12:43:42+00:00" }, { "name": "doctrine/annotations", @@ -8897,7 +8897,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8921,5 +8921,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.2.0" } From fe8c4cb4797ec909ee3e8ee1e4c7107b4d9c646e Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 13 Nov 2025 15:59:12 +0530 Subject: [PATCH 132/167] fix: generation of all response models in case of multi method endpoints --- .../SDK/Specification/Format/Swagger2.php | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/SDK/Specification/Format/Swagger2.php b/src/Appwrite/SDK/Specification/Format/Swagger2.php index d497369b9a..7606c48750 100644 --- a/src/Appwrite/SDK/Specification/Format/Swagger2.php +++ b/src/Appwrite/SDK/Specification/Format/Swagger2.php @@ -264,11 +264,20 @@ class Swagger2 extends Format } foreach ($methodObj->getResponses() as $response) { - /** @var Response $response */ - if (\is_array($response->getModel())) { + /** @var Response|array $response */ + $responseModel = $response->getModel(); + if (\is_array($responseModel)) { + foreach ($responseModel as $modelName) { + foreach ($this->models as $value) { + if ($value->getType() === $modelName) { + $usedModels[] = $modelName; + break; + } + } + } $additionalMethod['responses'][] = [ 'code' => $response->getCode(), - 'model' => \array_map(fn ($m) => '#/definitions/' . $m, $response->getModel()) + 'model' => \array_map(fn ($m) => '#/definitions/' . $m, $responseModel) ]; } else { $responseData = [ @@ -277,7 +286,13 @@ class Swagger2 extends Format // lets not assume stuff here! if ($response->getCode() !== 204) { - $responseData['model'] = '#/definitions/' . $response->getModel(); + $responseData['model'] = '#/definitions/' . $responseModel; + foreach ($this->models as $value) { + if ($value->getType() === $responseModel) { + $usedModels[] = $responseModel; + break; + } + } } $additionalMethod['responses'][] = $responseData; From 3bbd87ecb2dad1847168bce80776f0efe6fe443d Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 13 Nov 2025 16:05:27 +0530 Subject: [PATCH 133/167] fix: openapi too --- .../SDK/Specification/Format/OpenAPI3.php | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php index 38613313db..0ab16d306b 100644 --- a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php @@ -255,10 +255,21 @@ class OpenAPI3 extends Format } foreach ($methodObj->getResponses() as $response) { - if (\is_array($response->getModel())) { + /** @var Response|array $response */ + $responseModel = $response->getModel(); + + if (\is_array($responseModel)) { + foreach ($responseModel as $modelName) { + foreach ($this->models as $value) { + if ($value->getType() === $modelName) { + $usedModels[] = $modelName; + break; + } + } + } $additionalMethod['responses'][] = [ 'code' => $response->getCode(), - 'model' => \array_map(fn ($m) => '#/components/schemas/' . $m, $response->getModel()) + 'model' => \array_map(fn ($m) => '#/components/schemas/' . $m, $responseModel) ]; } else { $responseData = [ @@ -267,7 +278,13 @@ class OpenAPI3 extends Format // lets not assume stuff here! if ($response->getCode() !== 204) { - $responseData['model'] = '#/components/schemas/' . $response->getModel(); + $responseData['model'] = '#/components/schemas/' . $responseModel; + foreach ($this->models as $value) { + if ($value->getType() === $responseModel) { + $usedModels[] = $responseModel; + break; + } + } } $additionalMethod['responses'][] = $responseData; From b2d228e102bdebd00f67854d8cfe9d6e8631a159 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Thu, 13 Nov 2025 23:42:13 +1300 Subject: [PATCH 134/167] Update specs --- app/config/specs/open-api3-1.8.x-console.json | 8 +------- app/config/specs/open-api3-latest-console.json | 8 +------- app/config/specs/swagger2-1.8.x-console.json | 9 +-------- app/config/specs/swagger2-latest-console.json | 9 +-------- 4 files changed, 4 insertions(+), 30 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 287c33e5ec..ccf430cb28 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -22902,7 +22902,7 @@ "tags": [ "migrations" ], - "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in an Appwrite Storage bucket.", + "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete.", "responses": { "202": { "description": "Migration", @@ -22952,11 +22952,6 @@ "description": "Composite ID in the format {databaseId:collectionId}, identifying a collection within a database to export.", "x-example": "<ID1:ID2>" }, - "bucketId": { - "type": "string", - "description": "Storage bucket unique ID where the exported CSV will be stored.", - "x-example": "<BUCKET_ID>" - }, "filename": { "type": "string", "description": "The name of the file to be created for the export, excluding the .csv extension.", @@ -23006,7 +23001,6 @@ }, "required": [ "resourceId", - "bucketId", "filename" ] } diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 287c33e5ec..ccf430cb28 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -22902,7 +22902,7 @@ "tags": [ "migrations" ], - "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in an Appwrite Storage bucket.", + "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete.", "responses": { "202": { "description": "Migration", @@ -22952,11 +22952,6 @@ "description": "Composite ID in the format {databaseId:collectionId}, identifying a collection within a database to export.", "x-example": "<ID1:ID2>" }, - "bucketId": { - "type": "string", - "description": "Storage bucket unique ID where the exported CSV will be stored.", - "x-example": "<BUCKET_ID>" - }, "filename": { "type": "string", "description": "The name of the file to be created for the export, excluding the .csv extension.", @@ -23006,7 +23001,6 @@ }, "required": [ "resourceId", - "bucketId", "filename" ] } diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 4562120363..2d52da1db7 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -23005,7 +23005,7 @@ "tags": [ "migrations" ], - "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in an Appwrite Storage bucket.", + "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete.", "responses": { "202": { "description": "Migration", @@ -23053,12 +23053,6 @@ "default": null, "x-example": "<ID1:ID2>" }, - "bucketId": { - "type": "string", - "description": "Storage bucket unique ID where the exported CSV will be stored.", - "default": null, - "x-example": "<BUCKET_ID>" - }, "filename": { "type": "string", "description": "The name of the file to be created for the export, excluding the .csv extension.", @@ -23116,7 +23110,6 @@ }, "required": [ "resourceId", - "bucketId", "filename" ] } diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 4562120363..2d52da1db7 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -23005,7 +23005,7 @@ "tags": [ "migrations" ], - "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in an Appwrite Storage bucket.", + "description": "Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete.", "responses": { "202": { "description": "Migration", @@ -23053,12 +23053,6 @@ "default": null, "x-example": "<ID1:ID2>" }, - "bucketId": { - "type": "string", - "description": "Storage bucket unique ID where the exported CSV will be stored.", - "default": null, - "x-example": "<BUCKET_ID>" - }, "filename": { "type": "string", "description": "The name of the file to be created for the export, excluding the .csv extension.", @@ -23116,7 +23110,6 @@ }, "required": [ "resourceId", - "bucketId", "filename" ] } From 3df2efb7aec7515ac51ecbdb1722694c9ce25079 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 00:15:18 +1300 Subject: [PATCH 135/167] Fix file reads --- app/controllers/api/storage.php | 13 ++++++++----- src/Appwrite/Platform/Workers/Migrations.php | 15 +++++++++++---- tests/e2e/Services/Migrations/MigrationsBase.php | 15 +++++++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 72acd7b4a2..d4adfe27cf 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1477,12 +1477,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->inject('response') ->inject('request') ->inject('dbForProject') + ->inject('dbForPlatform') ->inject('project') ->inject('mode') ->inject('deviceForFiles') - ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Document $project, string $mode, Device $deviceForFiles) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - + ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Database $dbForPlatform, Document $project, string $mode, Device $deviceForFiles) { $decoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0); try { @@ -1499,15 +1498,19 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') throw new Exception(Exception::USER_UNAUTHORIZED); } + // Check if this is an internal/platform file based on JWT flag + $isInternal = $decoded['internal'] ?? false; + $db = $isInternal ? $dbForPlatform : $dbForProject; + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $bucket = Authorization::skip(fn () => $db->getDocument('buckets', $bucketId)); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); - + $file = Authorization::skip(fn () => $db->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 42d81d8999..875dca57ce 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -11,7 +11,7 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Exception\Authorization; +use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; @@ -19,6 +19,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Locale\Locale; use Utopia\Migration\Destination; use Utopia\Migration\Destinations\Appwrite as DestinationAppwrite; @@ -225,7 +226,7 @@ class Migrations extends Action } /** - * @throws Authorization + * @throws AuthorizationException * @throws Structure * @throws Conflict * @throws \Utopia\Database\Exception @@ -284,7 +285,7 @@ class Migrations extends Action } /** - * @throws Authorization + * @throws AuthorizationException * @throws Conflict * @throws Restricted * @throws Structure @@ -423,7 +424,7 @@ class Migrations extends Action * @param Document $migration * @param Mail $queueForMails * @return void - * @throws Authorization + * @throws AuthorizationException * @throws Structure * @throws \Utopia\Database\Exception * @throws Exception @@ -445,6 +446,11 @@ class Migrations extends Action throw new \Exception('User ' . $userInternalId . ' not found'); } + $bucket = Authorization::skip(fn () => $this->dbForPlatform->getDocument('buckets', $bucketId)); + if ($bucket->isEmpty()) { + throw new \Exception('Bucket not found'); + } + $path = $this->deviceForFiles->getPath($bucketId . '/' . $this->sanitizeFilename($filename) . '.csv'); $size = $this->deviceForFiles->getFileSize($path); $mime = $this->deviceForFiles->getFileMimeType($path); @@ -517,6 +523,7 @@ class Migrations extends Action 'bucketId' => $bucketId, 'fileId' => $fileId, 'projectId' => $project->getId(), + 'internal' => true, ]); // Generate download URL with JWT diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index a6ee9c15d5..f16864960e 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1341,16 +1341,15 @@ trait MigrationsBase $path = \str_replace('/v1', '', $components['path']); $downloadWithJwt = $this->client->call(Client::METHOD_GET, $path . '?project=' . $queryParams['project'] . '&jwt=' . $queryParams['jwt']); $this->assertEquals(200, $downloadWithJwt['headers']['status-code'], 'Failed to download file with JWT'); - $this->assertEquals($csvContent, $downloadWithJwt['body'], 'Downloaded content differs from original'); - // Test that download without JWT fails - $downloadWithoutJwt = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download'); - $this->assertEquals(404, $downloadWithoutJwt['headers']['status-code'], 'File should not be downloadable without JWT'); + // Verify the downloaded content is valid CSV + $csvData = $downloadWithJwt['body']; + $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->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]); + // Cleanup $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [ 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] From b9211d7141cb932214272b6a80fd87de7976ae76 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 15:55:41 +1300 Subject: [PATCH 136/167] Add delete old CSV job for maintenance --- app/controllers/api/storage.php | 7 ++-- app/init/constants.php | 1 + src/Appwrite/Platform/Tasks/Maintenance.php | 8 +++++ src/Appwrite/Platform/Workers/Deletes.php | 38 +++++++++++++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 9cd3575b52..13234513c0 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1499,19 +1499,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') throw new Exception(Exception::USER_UNAUTHORIZED); } - // Check if this is an internal/platform file based on JWT flag $isInternal = $decoded['internal'] ?? false; - $db = $isInternal ? $dbForPlatform : $dbForProject; + $dbForProject = $isInternal ? $dbForPlatform : $dbForProject; $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $bucket = Authorization::skip(fn () => $db->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = Authorization::skip(fn () => $db->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } diff --git a/app/init/constants.php b/app/init/constants.php index 3b81785690..e11fdf9a54 100644 --- a/app/init/constants.php +++ b/app/init/constants.php @@ -138,6 +138,7 @@ const DELETE_TYPE_TOPIC = 'topic'; const DELETE_TYPE_TARGET = 'target'; const DELETE_TYPE_EXPIRED_TARGETS = 'invalid_targets'; const DELETE_TYPE_SESSION_TARGETS = 'session_targets'; +const DELETE_TYPE_CSV_EXPORTS = 'csv_exports'; const DELETE_TYPE_MAINTENANCE = 'maintenance'; // Message types diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php index 036e8783d4..f5785d0bb4 100644 --- a/src/Appwrite/Platform/Tasks/Maintenance.php +++ b/src/Appwrite/Platform/Tasks/Maintenance.php @@ -95,6 +95,7 @@ class Maintenance extends Action $this->renewCertificates($dbForPlatform, $queueForCertificates); $this->notifyDeleteCache($cacheRetention, $queueForDeletes); $this->notifyDeleteSchedules($schedulesDeletionRetention, $queueForDeletes); + $this->notifyDeleteCSVExports($queueForDeletes); }, $interval, $delay); } @@ -106,6 +107,13 @@ class Maintenance extends Action ->trigger(); } + private function notifyDeleteCSVExports(Delete $queueForDeletes): void + { + $queueForDeletes + ->setType(DELETE_TYPE_CSV_EXPORTS) + ->trigger(); + } + private function renewCertificates(Database $dbForPlatform, Certificate $queueForCertificate): void { $time = DatabaseDateTime::now(); diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 331a2668a3..964eddaad3 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -179,6 +179,9 @@ class Deletes extends Action case DELETE_TYPE_SESSION_TARGETS: $this->deleteSessionTargets($project, $getProjectDB, $document); break; + case DELETE_TYPE_CSV_EXPORTS: + $this->deleteOldCSVExports($dbForPlatform, $deviceForFiles); + break; case DELETE_TYPE_MAINTENANCE: $this->deleteExpiredTargets($project, $getProjectDB); $this->deleteExecutionLogs($project, $getProjectDB, $executionRetention); @@ -720,6 +723,41 @@ class Deletes extends Action ], $dbForProject); } + /** + * @param Database $dbForPlatform + * @param Device $deviceForFiles + * @return void + * @throws Exception|Throwable + */ + private function deleteOldCSVExports(Database $dbForPlatform, Device $deviceForFiles): void + { + $bucket = $dbForPlatform->getDocument('buckets', 'default'); + + if ($bucket->isEmpty()) { + Console::warning('Default bucket not found, skipping CSV export cleanup'); + return; + } + + $oneWeekAgo = DateTime::addSeconds(new \DateTime(), -1 * 60 * 60 * 24 * 7); // 1 week + + Console::info("Deleting CSV export files older than " . $oneWeekAgo); + + $this->deleteByGroup('bucket_' . $bucket->getSequence(), [ + Query::select([...$this->selects, '$createdAt', 'filename', 'path']), + Query::equal('bucketId', ['default']), + Query::endsWith('filename', ['.csv']), + Query::createdBefore($oneWeekAgo), + Query::orderDesc('$createdAt'), + Query::orderDesc(), + ], $dbForPlatform, function (Document $file) use ($deviceForFiles) { + $path = $file->getAttribute('path'); + if ($deviceForFiles->exists($path)) { + $deviceForFiles->delete($path); + Console::success('Deleted CSV file: ' . $file->getAttribute('name')); + } + }); + } + /** * @param Database $dbForPlatform * @param string $datetime From 0588fb405d8c4cb745396e7f8cfd2fa635f2dd1a Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 16:16:06 +1300 Subject: [PATCH 137/167] Fix keys --- src/Appwrite/Platform/Workers/Deletes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 964eddaad3..7df2770ac6 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -743,10 +743,10 @@ class Deletes extends Action Console::info("Deleting CSV export files older than " . $oneWeekAgo); $this->deleteByGroup('bucket_' . $bucket->getSequence(), [ - Query::select([...$this->selects, '$createdAt', 'filename', 'path']), + Query::select([...$this->selects, '$createdAt', 'name', 'path']), Query::equal('bucketId', ['default']), - Query::endsWith('filename', ['.csv']), Query::createdBefore($oneWeekAgo), + Query::endsWith('name', ['.csv']), Query::orderDesc('$createdAt'), Query::orderDesc(), ], $dbForPlatform, function (Document $file) use ($deviceForFiles) { From 72c71785a60a31579c4a7b90eef316252bc9abdf Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 16:35:10 +1300 Subject: [PATCH 138/167] Fix doc --- src/Appwrite/Platform/Workers/Migrations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 875dca57ce..0bd5c50e04 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -546,7 +546,7 @@ class Migrations extends Action * * @param bool $success Whether the export was successful * @param Document $project - * @param string $user The user who triggered the operation + * @param Document $user The user who triggered the operation * @param array $options Migration options * @param Mail $queueForMails * @param string $downloadUrl Download URL for successful exports From 2ab36f4cd6d74001bbd91dac2eb0962799d9d6e0 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 16:40:00 +1300 Subject: [PATCH 139/167] Use helper for tests --- .../TablesDB/Transactions/TransactionsBase.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php index 09f62d165d..7e223644b2 100644 --- a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php +++ b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php @@ -2,6 +2,7 @@ namespace Tests\E2E\Services\Databases\TablesDB\Transactions; +use Appwrite\Operator; use Tests\E2E\Client; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -5645,7 +5646,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'items' => '{"method":"arrayRemove","attribute":"","values":["item2"]}' + 'items' => Operator::arrayRemove('item2') ] ]); @@ -5658,7 +5659,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'items' => '{"method":"arrayInsert","attribute":"","values":[2,"newItem"]}' + 'items' => Operator::arrayInsert(2, 'newItem') ] ]); @@ -5773,7 +5774,7 @@ trait TransactionsBase 'tableId' => $tableId, 'rowId' => 'doc1', 'data' => [ - 'tags' => '{"method":"arrayRemove","attribute":"","values":["javascript"]}' + 'tags' => Operator::arrayRemove('javascript') ] ], [ @@ -5782,7 +5783,7 @@ trait TransactionsBase 'tableId' => $tableId, 'rowId' => 'doc1', 'data' => [ - 'tags' => '{"method":"arrayAppend","attribute":"","values":["go","rust"]}' + 'tags' => Operator::arrayAppend(['go', 'rust']) ] ] ] @@ -5905,7 +5906,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'list1' => '{"method":"arrayPrepend","attribute":"","values":["z"]}' + 'list1' => Operator::arrayPrepend(['z']) ] ]); @@ -5916,7 +5917,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'list2' => '{"method":"arrayAppend","attribute":"","values":["w"]}' + 'list2' => Operator::arrayAppend(['w']) ] ]); @@ -5927,7 +5928,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'list3' => '{"method":"arrayRemove","attribute":"","values":["3"]}' + 'list3' => Operator::arrayRemove('3') ] ]); From afb0fcbc6f9f5903a5850ed4f7ab76d74edda543 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 16:45:21 +1300 Subject: [PATCH 140/167] Update DB --- composer.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index 8692e3e3de..8a91ad171e 100644 --- a/composer.lock +++ b/composer.lock @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "4.2.0", + "version": "4.3.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "3038eb6336dfef6da3f4d68178baa70d00cfc906" + "reference": "fe7a1326ad623609e65587fe8c01a630a7075fee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/3038eb6336dfef6da3f4d68178baa70d00cfc906", - "reference": "3038eb6336dfef6da3f4d68178baa70d00cfc906", + "url": "https://api.github.com/repos/utopia-php/database/zipball/fe7a1326ad623609e65587fe8c01a630a7075fee", + "reference": "fe7a1326ad623609e65587fe8c01a630a7075fee", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/4.2.0" + "source": "https://github.com/utopia-php/database/tree/4.3.0" }, - "time": "2025-11-12T09:03:35+00:00" + "time": "2025-11-14T03:43:10+00:00" }, { "name": "utopia-php/detector", @@ -8718,16 +8718,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", "shasum": "" }, "require": { @@ -8756,7 +8756,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.0" }, "funding": [ { @@ -8764,7 +8764,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-13T13:44:09+00:00" }, { "name": "twig/twig", @@ -8897,7 +8897,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8921,5 +8921,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } From ab90563989a85e83b156b39d22754bdb9bd1ff37 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 17:31:17 +1300 Subject: [PATCH 141/167] Fix tests --- .../TablesDB/Transactions/TransactionsBase.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php index 7e223644b2..488dc60239 100644 --- a/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php +++ b/tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php @@ -2,11 +2,11 @@ namespace Tests\E2E\Services\Databases\TablesDB\Transactions; -use Appwrite\Operator; use Tests\E2E\Client; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Operator; use Utopia\Database\Query; trait TransactionsBase @@ -5646,7 +5646,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'items' => Operator::arrayRemove('item2') + 'items' => Operator::arrayRemove('item2')->toString() ] ]); @@ -5659,7 +5659,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'items' => Operator::arrayInsert(2, 'newItem') + 'items' => Operator::arrayInsert(2, 'newItem')->toString() ] ]); @@ -5774,7 +5774,7 @@ trait TransactionsBase 'tableId' => $tableId, 'rowId' => 'doc1', 'data' => [ - 'tags' => Operator::arrayRemove('javascript') + 'tags' => Operator::arrayRemove('javascript')->toString() ] ], [ @@ -5783,7 +5783,7 @@ trait TransactionsBase 'tableId' => $tableId, 'rowId' => 'doc1', 'data' => [ - 'tags' => Operator::arrayAppend(['go', 'rust']) + 'tags' => Operator::arrayAppend(['go', 'rust'])->toString() ] ] ] @@ -5906,7 +5906,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'list1' => Operator::arrayPrepend(['z']) + 'list1' => Operator::arrayPrepend(['z'])->toString() ] ]); @@ -5917,7 +5917,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'list2' => Operator::arrayAppend(['w']) + 'list2' => Operator::arrayAppend(['w'])->toString() ] ]); @@ -5928,7 +5928,7 @@ trait TransactionsBase ], $this->getHeaders()), [ 'transactionId' => $transactionId, 'data' => [ - 'list3' => Operator::arrayRemove('3') + 'list3' => Operator::arrayRemove('3')->toString() ] ]); From 2349401a865cfb1124476610b82913dc1c46f962 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 18:49:26 +1300 Subject: [PATCH 142/167] Fix merge --- .../Databases/Http/Databases/Transactions/Update.php | 2 +- src/Appwrite/Platform/Workers/Migrations.php | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index bf84b05e04..ec5f0e4c04 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -166,7 +166,7 @@ class Update extends Action } if (!isset($collections[$collectionId])) { - $collections[$collectionId] = Authorization::skip( + $collections[$collectionId] = $authorization->skip( fn () => $dbForProject->getCollection($collectionId) ); } diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 0bd5c50e04..0dff335f4d 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -84,6 +84,7 @@ class Migrations extends Action ->inject('deviceForFiles') ->inject('queueForMails') ->inject('plan') + ->inject('authorization') ->callback($this->action(...)); } @@ -101,6 +102,7 @@ class Migrations extends Action Device $deviceForFiles, Mail $queueForMails, array $plan, + Authorization $authorization, ): void { $payload = $message->getPayload() ?? []; $this->deviceForMigrations = $deviceForMigrations; @@ -127,7 +129,7 @@ class Migrations extends Action return; } - $this->processMigration($migration, $queueForRealtime, $queueForMails); + $this->processMigration($migration, $queueForRealtime, $queueForMails, $authorization); } /** @@ -296,6 +298,7 @@ class Migrations extends Action Document $migration, Realtime $queueForRealtime, Mail $queueForMails, + Authorization $authorization, ): void { $project = $this->dbForPlatform->getDocument('projects', $this->project->getId()); $tempAPIKey = $this->generateAPIKey($project); @@ -432,7 +435,8 @@ class Migrations extends Action protected function handleCSVExportComplete( Document $project, Document $migration, - Mail $queueForMails + Mail $queueForMails, + Authorization $authorization, ): void { $options = $migration->getAttribute('options', []); $bucketId = 'default'; // Always use platform default bucket @@ -446,7 +450,7 @@ class Migrations extends Action throw new \Exception('User ' . $userInternalId . ' not found'); } - $bucket = Authorization::skip(fn () => $this->dbForPlatform->getDocument('buckets', $bucketId)); + $bucket = $authorization->skip(fn () => $this->dbForPlatform->getDocument('buckets', $bucketId)); if ($bucket->isEmpty()) { throw new \Exception('Bucket not found'); } From c961316f464a59d3040dc9f993d8a802d298d46a Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Fri, 14 Nov 2025 19:08:33 +1300 Subject: [PATCH 143/167] Fix params --- src/Appwrite/Platform/Workers/Migrations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 0dff335f4d..08782fd825 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -414,7 +414,7 @@ class Migrations extends Action $source?->success(); if ($migration->getAttribute('destination') === DestinationCSV::getName()) { - $this->handleCSVExportComplete($project, $migration, $queueForMails); + $this->handleCSVExportComplete($project, $migration, $queueForMails, $authorization); } } } From 38ef0ad399df704721af79a36faf419730b74758 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Fri, 14 Nov 2025 12:39:37 +0530 Subject: [PATCH 144/167] fix: release sdks doc --- docs/tutorials/release-sdks.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/release-sdks.md b/docs/tutorials/release-sdks.md index 0e03beca71..99c0fa4fd3 100644 --- a/docs/tutorials/release-sdks.md +++ b/docs/tutorials/release-sdks.md @@ -26,27 +26,34 @@ Before releasing SDKs, you need to: To enable SDK releases via GitHub, you need to mount SSH keys and configure GitHub authentication in your Docker environment. -#### Update docker-compose.override.yml +#### Update Dockerfile -Update `docker-compose.override.yml` to mount SSH keys and set environment variables for the `appwrite` service: +Add the following configuration to your `Dockerfile`: + +```dockerfile +ARG GH_TOKEN +ENV GH_TOKEN=your_github_token_here +RUN git config --global user.email "your-email@example.com" +RUN apk add --update --no-cache openssh-client github-cli +``` + +Replace: +- `your_github_token_here` with your GitHub personal access token (with appropriate permissions) +- `your-email@example.com` with your Git email address + +#### Update docker-compose.yml + +Add the SSH key volume mount to the `appwrite` service in `docker-compose.yml`: ```yaml services: appwrite: volumes: - ~/.ssh:/root/.ssh - environment: - - GH_TOKEN=your_github_token_here - - GIT_EMAIL=your-email@example.com + # ... other volumes ``` -Uncomment the volumes section. - -Replace: -- `your_github_token_here` with your GitHub personal access token (with appropriate permissions) -- `your-email@example.com` with your Git email address - -This mounts your SSH keys from the host machine and sets the GitHub token and email as environment variables, allowing the container to authenticate with GitHub. The git configuration is handled automatically at runtime. +This mounts your SSH keys from the host machine, allowing the container to authenticate with GitHub. ### Updating Specs From cc7b5b7dcff7143ed165447a622484ac806396fa Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Fri, 14 Nov 2025 15:05:32 +0530 Subject: [PATCH 145/167] fix: missing nullable in datetime --- .../Http/Databases/Collections/Attributes/Datetime/Create.php | 3 ++- .../Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php index 1f2098e7af..d0f45dc664 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php @@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends Action { @@ -63,7 +64,7 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, fn (Database $dbForProject) => new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime()), 'Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.', true, ['dbForProject']) + ->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.', true, ['dbForProject']) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php index db5a3059f1..69d6bd2b4b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php @@ -13,6 +13,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends DatetimeCreate { @@ -55,7 +56,7 @@ class Create extends DatetimeCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, fn (Database $dbForProject) => new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime()), 'Default value for the column in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.', true, ['dbForProject']) + ->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for the column in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.', true, ['dbForProject']) ->param('array', false, new Boolean(), 'Is column an array?', true) ->inject('response') ->inject('dbForProject') From db1b87ecbb79a9e17d545fd3a017773cf681de36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Fri, 14 Nov 2025 15:49:19 +0100 Subject: [PATCH 146/167] Add env var value detection --- app/controllers/api/vcs.php | 32 +++++++++---- src/Appwrite/Utopia/Response.php | 3 ++ .../Utopia/Response/Model/Detection.php | 22 +++++++++ .../Response/Model/DetectionFramework.php | 12 ++--- .../Response/Model/DetectionRuntime.php | 12 ++--- .../Response/Model/DetectionVariable.php | 46 +++++++++++++++++++ 6 files changed, 101 insertions(+), 26 deletions(-) create mode 100644 src/Appwrite/Utopia/Response/Model/Detection.php create mode 100644 src/Appwrite/Utopia/Response/Model/DetectionVariable.php diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index fd4d04cbd0..2ac6cd0b26 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -966,14 +966,14 @@ App::post('/v1/vcs/github/installations/:installationId/detections') } $wg = new WaitGroup(); - $envNames = []; + $envs = []; foreach ($files as $file) { if (!(\str_starts_with($file, '.env'))) { continue; } $wg->add(); - go(function () use ($github, $owner, $repositoryName, $providerRootDirectory, $file, $wg, &$envNames) { + go(function () use ($github, $owner, $repositoryName, $providerRootDirectory, $file, $wg, &$envs) { try { $contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/' . $file); $envFile = $contentResponse['content'] ?? ''; @@ -982,8 +982,9 @@ App::post('/v1/vcs/github/installations/:installationId/detections') foreach ($envLines as $line) { $parts = \explode('=', $line, 2); $envName = \trim($parts[0] ?? ''); + $envValue = \trim($parts[1] ?? ''); if (!empty($envName)) { - $envNames[] = $envName; + $envs[$envName] = $envValue; } } } finally { @@ -993,7 +994,15 @@ App::post('/v1/vcs/github/installations/:installationId/detections') } $wg->wait(); - $output->setAttribute('variables', \array_unique($envNames)); + $variables = []; + foreach ($envs as $key => $value) { + $variables[] = [ + 'name' => $key, + 'value' => $value, + ]; + } + + $output->setAttribute('variables', $variables); $response->dynamic($output, $type === 'framework' ? Response::MODEL_DETECTION_FRAMEWORK : Response::MODEL_DETECTION_RUNTIME); }); @@ -1171,14 +1180,14 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') } $wg = new WaitGroup(); - $envNames = []; + $envs = []; foreach ($files as $file) { if (!(\str_starts_with($file, '.env'))) { continue; } $wg->add(); - go(function () use ($github, $repo, $file, $wg, &$envNames) { + go(function () use ($github, $repo, $file, $wg, &$envs) { try { $contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], $file); $envFile = $contentResponse['content'] ?? ''; @@ -1187,8 +1196,9 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') foreach ($envLines as $line) { $parts = \explode('=', $line, 2); $envName = \trim($parts[0] ?? ''); + $envValue = \trim($parts[1] ?? ''); if (!empty($envName)) { - $envNames[] = $envName; + $envs[$envName] = $envValue; } } } finally { @@ -1198,7 +1208,13 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') } $wg->wait(); - $repo['variables'] = \array_unique($envNames); + $repo['variables'] = []; + foreach ($envs as $key => $value) { + $repo['variables'][] = [ + 'name' => $key, + 'value' => $value, + ]; + } return $repo; }; diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index b391f0ea72..19a451e2c0 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -59,6 +59,7 @@ use Appwrite\Utopia\Response\Model\Database; use Appwrite\Utopia\Response\Model\Deployment; use Appwrite\Utopia\Response\Model\DetectionFramework; use Appwrite\Utopia\Response\Model\DetectionRuntime; +use Appwrite\Utopia\Response\Model\DetectionVariable; use Appwrite\Utopia\Response\Model\DevKey; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Error; @@ -316,6 +317,7 @@ class Response extends SwooleResponse public const MODEL_BRANCH = 'branch'; public const MODEL_BRANCH_LIST = 'branchList'; public const MODEL_DETECTION_FRAMEWORK = 'detectionFramework'; + public const MODEL_DETECTION_VARIABLE = 'detectionVariable'; public const MODEL_DETECTION_RUNTIME = 'detectionRuntime'; public const MODEL_VCS_CONTENT = 'vcsContent'; public const MODEL_VCS_CONTENT_LIST = 'vcsContentList'; @@ -563,6 +565,7 @@ class Response extends SwooleResponse ->setModel(new ProviderRepositoryRuntime()) ->setModel(new DetectionFramework()) ->setModel(new DetectionRuntime()) + ->setModel(new DetectionVariable()) ->setModel(new VcsContent()) ->setModel(new Branch()) ->setModel(new Runtime()) diff --git a/src/Appwrite/Utopia/Response/Model/Detection.php b/src/Appwrite/Utopia/Response/Model/Detection.php new file mode 100644 index 0000000000..007182d1e9 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Detection.php @@ -0,0 +1,22 @@ +<?php + +namespace Appwrite\Utopia\Response\Model; + +use Appwrite\Utopia\Response; +use Appwrite\Utopia\Response\Model; + +abstract class Detection extends Model +{ + public function __construct() + { + $this + ->addRule('variables', [ + 'type' => Response::MODEL_DETECTION_VARIABLE, + 'description' => 'Environment variables found in .env files', + 'required' => false, + 'default' => [], + 'example' => new \stdClass(), + 'array' => true, + ]); + } +} diff --git a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php index 899ad8766e..4cdf37bbcf 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php @@ -3,12 +3,13 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model; -class DetectionFramework extends Model +class DetectionFramework extends Detection { public function __construct() { + parent::__construct(); + $this ->addRule('framework', [ 'type' => self::TYPE_STRING, @@ -33,13 +34,6 @@ class DetectionFramework extends Model 'description' => 'Site Output Directory', 'default' => '', 'example' => 'dist', - ]) - ->addRule('variables', [ - 'type' => self::TYPE_STRING, - 'description' => 'Environment variables found in .env files', - 'default' => [], - 'array' => true, - 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php index 20fde90491..1e63929092 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php @@ -3,12 +3,13 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model; -class DetectionRuntime extends Model +class DetectionRuntime extends Detection { public function __construct() { + parent::__construct(); + $this ->addRule('runtime', [ 'type' => self::TYPE_STRING, @@ -27,13 +28,6 @@ class DetectionRuntime extends Model 'description' => 'Function install and build commands', 'default' => '', 'example' => 'npm install && npm run build', - ]) - ->addRule('variables', [ - 'type' => self::TYPE_STRING, - 'description' => 'Environment variables found in .env files', - 'default' => [], - 'array' => true, - 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionVariable.php b/src/Appwrite/Utopia/Response/Model/DetectionVariable.php new file mode 100644 index 0000000000..a5a2d2acc0 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/DetectionVariable.php @@ -0,0 +1,46 @@ +<?php + +namespace Appwrite\Utopia\Response\Model; + +use Appwrite\Utopia\Response; +use Appwrite\Utopia\Response\Model; + +class DetectionVariable extends Model +{ + public function __construct() + { + $this + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Name of environment variable', + 'default' => '', + 'example' => 'NODE_ENV', + ]) + ->addRule('value', [ + 'type' => self::TYPE_STRING, + 'description' => 'Value of environment variable', + 'default' => '', + 'example' => 'production', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'DetectionVariable'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_DETECTION_VARIABLE; + } +} From 793057c82394aaff6ce27d0222ddf62d440e257c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Fri, 14 Nov 2025 18:06:20 +0100 Subject: [PATCH 147/167] Update composer.lock --- composer.lock | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/composer.lock b/composer.lock index d0ea4e720a..bc61d61460 100644 --- a/composer.lock +++ b/composer.lock @@ -161,16 +161,16 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.19.1", + "version": "0.19.2", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae" + "reference": "e5c142519df5aced37de9c302971c29c079ce3d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/runtimes/zipball/7bd0cc3cb97de625d7b07230bd91b121f88e72ae", - "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae", + "url": "https://api.github.com/repos/appwrite/runtimes/zipball/e5c142519df5aced37de9c302971c29c079ce3d9", + "reference": "e5c142519df5aced37de9c302971c29c079ce3d9", "shasum": "" }, "require": { @@ -210,9 +210,9 @@ ], "support": { "issues": "https://github.com/appwrite/runtimes/issues", - "source": "https://github.com/appwrite/runtimes/tree/0.19.1" + "source": "https://github.com/appwrite/runtimes/tree/0.19.2" }, - "time": "2025-05-27T07:12:56+00:00" + "time": "2025-11-11T13:44:44+00:00" }, { "name": "beberlei/assert", @@ -756,16 +756,16 @@ }, { "name": "google/protobuf", - "version": "v4.33.0", + "version": "v4.33.1", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d" + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/b50269e23204e5ae859a326ec3d90f09efe3047d", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/0cd73ccf0cd26c3e72299cce1ea6144091a57e12", + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12", "shasum": "" }, "require": { @@ -794,9 +794,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.0" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.1" }, - "time": "2025-10-15T20:10:28+00:00" + "time": "2025-11-12T21:58:05+00:00" }, { "name": "league/csv", @@ -961,16 +961,16 @@ }, { "name": "mongodb/mongodb", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/mongodb/mongo-php-library.git", - "reference": "f399d24905dd42f97dfe0af9706129743ef247ac" + "reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/f399d24905dd42f97dfe0af9706129743ef247ac", - "reference": "f399d24905dd42f97dfe0af9706129743ef247ac", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/0a2472ba9cbb932f7e43a8770aedb2fc30612a67", + "reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67", "shasum": "" }, "require": { @@ -986,7 +986,7 @@ "require-dev": { "doctrine/coding-standard": "^12.0", "phpunit/phpunit": "^10.5.35", - "rector/rector": "^1.2", + "rector/rector": "^2.1.4", "squizlabs/php_codesniffer": "^3.7", "vimeo/psalm": "6.5.*" }, @@ -1032,9 +1032,9 @@ ], "support": { "issues": "https://github.com/mongodb/mongo-php-library/issues", - "source": "https://github.com/mongodb/mongo-php-library/tree/2.1.1" + "source": "https://github.com/mongodb/mongo-php-library/tree/2.1.2" }, - "time": "2025-08-13T20:50:05+00:00" + "time": "2025-10-06T12:12:40+00:00" }, { "name": "mustangostang/spyc", @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.2.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", + "url": "https://api.github.com/repos/utopia-php/database/zipball/e10b4faa4f3a3ef30a5f6d76acdb605469924aec", + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.2.0" + "source": "https://github.com/utopia-php/database/tree/3.4.0" }, - "time": "2025-11-06T05:41:54+00:00" + "time": "2025-11-13T06:34:20+00:00" }, { "name": "utopia-php/detector", @@ -4212,16 +4212,16 @@ }, { "name": "utopia-php/framework", - "version": "0.33.28", + "version": "0.33.29", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "5aaa94d406577b0059ad28c78022606890dc6de0" + "reference": "6e63939fdb33b847f92839499cd6e8df626c278d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/5aaa94d406577b0059ad28c78022606890dc6de0", - "reference": "5aaa94d406577b0059ad28c78022606890dc6de0", + "url": "https://api.github.com/repos/utopia-php/http/zipball/6e63939fdb33b847f92839499cd6e8df626c278d", + "reference": "6e63939fdb33b847f92839499cd6e8df626c278d", "shasum": "" }, "require": { @@ -4253,9 +4253,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/0.33.28" + "source": "https://github.com/utopia-php/http/tree/0.33.29" }, - "time": "2025-09-25T10:44:24+00:00" + "time": "2025-11-14T06:33:29+00:00" }, { "name": "utopia-php/image", @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.3", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" + "reference": "1f3686e41a2d10829220b74f54c80a770e9f968a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1f3686e41a2d10829220b74f54c80a770e9f968a", + "reference": "1f3686e41a2d10829220b74f54c80a770e9f968a", "shasum": "" }, "require": { @@ -5428,9 +5428,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.5.3" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.5" }, - "time": "2025-11-10T09:50:41+00:00" + "time": "2025-11-14T05:56:33+00:00" }, { "name": "doctrine/annotations", @@ -8718,16 +8718,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", "shasum": "" }, "require": { @@ -8756,7 +8756,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.0" }, "funding": [ { @@ -8764,7 +8764,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-13T13:44:09+00:00" }, { "name": "twig/twig", From 3568af54b3176612bcd9e1e50959401cb23c20a3 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 09:51:20 +0530 Subject: [PATCH 148/167] consistent naming --- app/controllers/api/storage.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index df177bc8e5..c2adc1e195 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -980,14 +980,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') /* @type Document $bucket */ $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAppUser = Auth::isAppUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser($authorization->getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$bucket->getAttribute('transformations', true) && !$isAppUser && !$isPrivilegedUser) { + if (!$bucket->getAttribute('transformations', true) && !$isAPIKey && !$isPrivilegedUser) { throw new Exception(Exception::STORAGE_BUCKET_TRANSFORMATIONS_DISABLED); } From f9274dad3ffea75a546f4f282c2fa94c16faf650 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 09:53:13 +0530 Subject: [PATCH 149/167] regenerate specs --- app/config/specs/open-api3-1.8.x-console.json | 169 +++++++++++++++-- app/config/specs/open-api3-1.8.x-server.json | 73 ++++++-- .../specs/open-api3-latest-console.json | 127 ++++++++++++- app/config/specs/open-api3-latest-server.json | 31 +++- app/config/specs/swagger2-1.8.x-console.json | 175 ++++++++++++++++-- app/config/specs/swagger2-1.8.x-server.json | 77 ++++++-- app/config/specs/swagger2-latest-console.json | 131 ++++++++++++- app/config/specs/swagger2-latest-server.json | 33 +++- 8 files changed, 728 insertions(+), 88 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 6b6ab7409f..fded6c46b0 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -7753,7 +7753,8 @@ "default": { "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -14414,10 +14415,22 @@ "description": "Path to function code in the template repo.", "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "x-example": "<VERSION>" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -14429,7 +14442,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -32314,10 +32328,22 @@ "description": "Path to site code in the template repo.", "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", - "x-example": "<VERSION>" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -32329,7 +32355,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -33455,7 +33482,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "schema": { "type": "array", @@ -33605,6 +33632,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -33799,6 +33831,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -36096,7 +36133,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "x-example": false }, "enabled": { @@ -36593,7 +36630,8 @@ "default": { "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -53579,6 +53617,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -53593,7 +53636,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -53612,7 +53656,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { @@ -54798,6 +54843,17 @@ "type": "string", "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" + }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] } }, "required": [ @@ -54807,7 +54863,8 @@ "provider", "private", "defaultBranch", - "pushedAt" + "pushedAt", + "variables" ], "example": { "id": "5e5ea5c16897e", @@ -54816,7 +54873,11 @@ "provider": "github", "private": true, "defaultBranch": "main", - "pushedAt": "datetime" + "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ] } }, "providerRepositoryFramework": { @@ -54858,6 +54919,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "framework": { "type": "string", "description": "Auto-detected framework. Empty if type is not \"framework\".", @@ -54872,6 +54944,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "framework" ], "example": { @@ -54882,6 +54955,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "framework": "nextjs" } }, @@ -54924,6 +55001,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "runtime": { "type": "string", "description": "Auto-detected runtime. Empty if type is not \"runtime\".", @@ -54938,6 +55026,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "runtime" ], "example": { @@ -54948,6 +55037,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "runtime": "node-22" } }, @@ -54955,6 +55048,15 @@ "description": "DetectionFramework", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "$ref": "#\/components\/schemas\/detectionVariable" + }, + "x-example": {}, + "nullable": true + }, "framework": { "type": "string", "description": "Framework", @@ -54983,6 +55085,7 @@ "outputDirectory" ], "example": { + "variables": {}, "framework": "nuxt", "installCommand": "npm install", "buildCommand": "npm run build", @@ -54993,6 +55096,15 @@ "description": "DetectionRuntime", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "$ref": "#\/components\/schemas\/detectionVariable" + }, + "x-example": {}, + "nullable": true + }, "runtime": { "type": "string", "description": "Runtime", @@ -55015,11 +55127,36 @@ "commands" ], "example": { + "variables": {}, "runtime": "node", "entrypoint": "index.js", "commands": "npm install && npm run build" } }, + "detectionVariable": { + "description": "DetectionVariable", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of environment variable", + "x-example": "NODE_ENV" + }, + "value": { + "type": "string", + "description": "Value of environment variable", + "x-example": "production" + } + }, + "required": [ + "name", + "value" + ], + "example": { + "name": "NODE_ENV", + "value": "production" + } + }, "vcsContent": { "description": "VcsContents", "type": "object", 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 8fc49b1db5..2cb6a74853 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -7222,7 +7222,8 @@ "default": { "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -13203,10 +13204,22 @@ "description": "Path to function code in the template repo.", "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the function template.", - "x-example": "<VERSION>" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -13218,7 +13231,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -22838,10 +22852,22 @@ "description": "Path to site code in the template repo.", "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", - "x-example": "<VERSION>" + "description": "Type for the reference provided. Can be commit, branch, or tag", + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -22853,7 +22879,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -23911,7 +23938,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "schema": { "type": "array", @@ -24062,6 +24089,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -24258,6 +24290,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -26342,7 +26379,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "x-example": false }, "enabled": { @@ -26844,7 +26881,8 @@ "default": { "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -42256,6 +42294,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -42270,7 +42313,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -42289,7 +42333,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 12d2d30ab9..fded6c46b0 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -7753,7 +7753,8 @@ "default": { "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -33481,7 +33482,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "schema": { "type": "array", @@ -33631,6 +33632,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -33825,6 +33831,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -36122,7 +36133,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "x-example": false }, "enabled": { @@ -36619,7 +36630,8 @@ "default": { "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -53605,6 +53617,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -53619,7 +53636,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -53638,7 +53656,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { @@ -54824,6 +54843,17 @@ "type": "string", "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" + }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] } }, "required": [ @@ -54833,7 +54863,8 @@ "provider", "private", "defaultBranch", - "pushedAt" + "pushedAt", + "variables" ], "example": { "id": "5e5ea5c16897e", @@ -54842,7 +54873,11 @@ "provider": "github", "private": true, "defaultBranch": "main", - "pushedAt": "datetime" + "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ] } }, "providerRepositoryFramework": { @@ -54884,6 +54919,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "framework": { "type": "string", "description": "Auto-detected framework. Empty if type is not \"framework\".", @@ -54898,6 +54944,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "framework" ], "example": { @@ -54908,6 +54955,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "framework": "nextjs" } }, @@ -54950,6 +55001,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "runtime": { "type": "string", "description": "Auto-detected runtime. Empty if type is not \"runtime\".", @@ -54964,6 +55026,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "runtime" ], "example": { @@ -54974,6 +55037,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "runtime": "node-22" } }, @@ -54981,6 +55048,15 @@ "description": "DetectionFramework", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "$ref": "#\/components\/schemas\/detectionVariable" + }, + "x-example": {}, + "nullable": true + }, "framework": { "type": "string", "description": "Framework", @@ -55009,6 +55085,7 @@ "outputDirectory" ], "example": { + "variables": {}, "framework": "nuxt", "installCommand": "npm install", "buildCommand": "npm run build", @@ -55019,6 +55096,15 @@ "description": "DetectionRuntime", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "$ref": "#\/components\/schemas\/detectionVariable" + }, + "x-example": {}, + "nullable": true + }, "runtime": { "type": "string", "description": "Runtime", @@ -55041,11 +55127,36 @@ "commands" ], "example": { + "variables": {}, "runtime": "node", "entrypoint": "index.js", "commands": "npm install && npm run build" } }, + "detectionVariable": { + "description": "DetectionVariable", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of environment variable", + "x-example": "NODE_ENV" + }, + "value": { + "type": "string", + "description": "Value of environment variable", + "x-example": "production" + } + }, + "required": [ + "name", + "value" + ], + "example": { + "name": "NODE_ENV", + "value": "production" + } + }, "vcsContent": { "description": "VcsContents", "type": "object", diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index b11c69442b..2cb6a74853 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -7222,7 +7222,8 @@ "default": { "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -23937,7 +23938,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "schema": { "type": "array", @@ -24088,6 +24089,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -24284,6 +24290,11 @@ "type": "boolean", "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "x-example": false } }, "required": [ @@ -26368,7 +26379,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "x-example": false }, "enabled": { @@ -26870,7 +26881,8 @@ "default": { "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -42282,6 +42294,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -42296,7 +42313,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -42315,7 +42333,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 384011f2fd..28a4f76c61 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -7851,7 +7851,8 @@ "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -14355,11 +14356,24 @@ "default": null, "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the function template.", + "description": "Type for the reference provided. Can be commit, branch, or tag", "default": null, - "x-example": "<VERSION>" + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": null, + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -14372,7 +14386,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -32416,11 +32431,24 @@ "default": null, "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", + "description": "Type for the reference provided. Can be commit, branch, or tag", "default": null, - "x-example": "<VERSION>" + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": null, + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -32433,7 +32461,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -33536,7 +33565,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "type": "array", "collectionFormat": "multi", @@ -33694,6 +33723,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -33893,6 +33928,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -36122,7 +36163,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": false, "x-example": false }, @@ -36610,7 +36651,8 @@ "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -53397,6 +53439,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -53411,7 +53458,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -53430,7 +53478,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { @@ -54623,6 +54672,17 @@ "type": "string", "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" + }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] } }, "required": [ @@ -54632,7 +54692,8 @@ "provider", "private", "defaultBranch", - "pushedAt" + "pushedAt", + "variables" ], "example": { "id": "5e5ea5c16897e", @@ -54641,7 +54702,11 @@ "provider": "github", "private": true, "defaultBranch": "main", - "pushedAt": "datetime" + "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ] } }, "providerRepositoryFramework": { @@ -54683,6 +54748,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "framework": { "type": "string", "description": "Auto-detected framework. Empty if type is not \"framework\".", @@ -54697,6 +54773,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "framework" ], "example": { @@ -54707,6 +54784,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "framework": "nextjs" } }, @@ -54749,6 +54830,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "runtime": { "type": "string", "description": "Auto-detected runtime. Empty if type is not \"runtime\".", @@ -54763,6 +54855,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "runtime" ], "example": { @@ -54773,6 +54866,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "runtime": "node-22" } }, @@ -54780,6 +54877,16 @@ "description": "DetectionFramework", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "object", + "$ref": "#\/definitions\/detectionVariable" + }, + "x-example": {}, + "x-nullable": true + }, "framework": { "type": "string", "description": "Framework", @@ -54808,6 +54915,7 @@ "outputDirectory" ], "example": { + "variables": {}, "framework": "nuxt", "installCommand": "npm install", "buildCommand": "npm run build", @@ -54818,6 +54926,16 @@ "description": "DetectionRuntime", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "object", + "$ref": "#\/definitions\/detectionVariable" + }, + "x-example": {}, + "x-nullable": true + }, "runtime": { "type": "string", "description": "Runtime", @@ -54840,11 +54958,36 @@ "commands" ], "example": { + "variables": {}, "runtime": "node", "entrypoint": "index.js", "commands": "npm install && npm run build" } }, + "detectionVariable": { + "description": "DetectionVariable", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of environment variable", + "x-example": "NODE_ENV" + }, + "value": { + "type": "string", + "description": "Value of environment variable", + "x-example": "production" + } + }, + "required": [ + "name", + "value" + ], + "example": { + "name": "NODE_ENV", + "value": "production" + } + }, "vcsContent": { "description": "VcsContents", "type": "object", diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index af417d5788..e760c1bb7d 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -7310,7 +7310,8 @@ "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -13171,11 +13172,24 @@ "default": null, "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the function template.", + "description": "Type for the reference provided. Can be commit, branch, or tag", "default": null, - "x-example": "<VERSION>" + "x-example": "commit", + "enum": [ + "commit", + "branch", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": null, + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -13188,7 +13202,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -22989,11 +23004,24 @@ "default": null, "x-example": "<ROOT_DIRECTORY>" }, - "version": { + "type": { "type": "string", - "description": "Version (tag) for the repo linked to the site template.", + "description": "Type for the reference provided. Can be commit, branch, or tag", "default": null, - "x-example": "<VERSION>" + "x-example": "branch", + "enum": [ + "branch", + "commit", + "tag" + ], + "x-enum-name": null, + "x-enum-keys": [] + }, + "reference": { + "type": "string", + "description": "Reference value, can be a commit hash, branch name, or release tag", + "default": null, + "x-example": "<REFERENCE>" }, "activate": { "type": "boolean", @@ -23006,7 +23034,8 @@ "repository", "owner", "rootDirectory", - "version" + "type", + "reference" ] } } @@ -24045,7 +24074,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "type": "array", "collectionFormat": "multi", @@ -24204,6 +24233,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -24405,6 +24440,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -26429,7 +26470,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": false, "x-example": false }, @@ -26922,7 +26963,8 @@ "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -42175,6 +42217,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -42189,7 +42236,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -42208,7 +42256,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index efa5d9bdee..28a4f76c61 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -7851,7 +7851,8 @@ "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -33564,7 +33565,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "type": "array", "collectionFormat": "multi", @@ -33722,6 +33723,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -33921,6 +33928,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -36150,7 +36163,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": false, "x-example": false }, @@ -36638,7 +36651,8 @@ "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -53425,6 +53439,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -53439,7 +53458,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -53458,7 +53478,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { @@ -54651,6 +54672,17 @@ "type": "string", "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" + }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] } }, "required": [ @@ -54660,7 +54692,8 @@ "provider", "private", "defaultBranch", - "pushedAt" + "pushedAt", + "variables" ], "example": { "id": "5e5ea5c16897e", @@ -54669,7 +54702,11 @@ "provider": "github", "private": true, "defaultBranch": "main", - "pushedAt": "datetime" + "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ] } }, "providerRepositoryFramework": { @@ -54711,6 +54748,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "framework": { "type": "string", "description": "Auto-detected framework. Empty if type is not \"framework\".", @@ -54725,6 +54773,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "framework" ], "example": { @@ -54735,6 +54784,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "framework": "nextjs" } }, @@ -54777,6 +54830,17 @@ "description": "Last commit date in ISO 8601 format.", "x-example": "datetime" }, + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "string" + }, + "x-example": [ + "PORT", + "NODE_ENV" + ] + }, "runtime": { "type": "string", "description": "Auto-detected runtime. Empty if type is not \"runtime\".", @@ -54791,6 +54855,7 @@ "private", "defaultBranch", "pushedAt", + "variables", "runtime" ], "example": { @@ -54801,6 +54866,10 @@ "private": true, "defaultBranch": "main", "pushedAt": "datetime", + "variables": [ + "PORT", + "NODE_ENV" + ], "runtime": "node-22" } }, @@ -54808,6 +54877,16 @@ "description": "DetectionFramework", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "object", + "$ref": "#\/definitions\/detectionVariable" + }, + "x-example": {}, + "x-nullable": true + }, "framework": { "type": "string", "description": "Framework", @@ -54836,6 +54915,7 @@ "outputDirectory" ], "example": { + "variables": {}, "framework": "nuxt", "installCommand": "npm install", "buildCommand": "npm run build", @@ -54846,6 +54926,16 @@ "description": "DetectionRuntime", "type": "object", "properties": { + "variables": { + "type": "array", + "description": "Environment variables found in .env files", + "items": { + "type": "object", + "$ref": "#\/definitions\/detectionVariable" + }, + "x-example": {}, + "x-nullable": true + }, "runtime": { "type": "string", "description": "Runtime", @@ -54868,11 +54958,36 @@ "commands" ], "example": { + "variables": {}, "runtime": "node", "entrypoint": "index.js", "commands": "npm install && npm run build" } }, + "detectionVariable": { + "description": "DetectionVariable", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of environment variable", + "x-example": "NODE_ENV" + }, + "value": { + "type": "string", + "description": "Value of environment variable", + "x-example": "production" + } + }, + "required": [ + "name", + "value" + ], + "example": { + "name": "NODE_ENV", + "value": "production" + } + }, "vcsContent": { "description": "VcsContents", "type": "object", diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index e48f00475a..e760c1bb7d 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -7310,7 +7310,8 @@ "type": "string", "description": "Default value for the attribute in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -24073,7 +24074,7 @@ "parameters": [ { "name": "queries", - "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus", + "description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations", "required": false, "type": "array", "collectionFormat": "multi", @@ -24232,6 +24233,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -24433,6 +24440,12 @@ "description": "Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled", "default": true, "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Are image transformations enabled?", + "default": true, + "x-example": false } }, "required": [ @@ -26457,7 +26470,7 @@ }, "rowSecurity": { "type": "boolean", - "description": "Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a document. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", + "description": "Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).", "default": false, "x-example": false }, @@ -26950,7 +26963,8 @@ "type": "string", "description": "Default value for the column in [ISO 8601](https:\/\/www.iso.org\/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.", "default": null, - "x-example": null + "x-example": null, + "x-nullable": true }, "array": { "type": "boolean", @@ -42203,6 +42217,11 @@ "type": "boolean", "description": "Virus scanning is enabled.", "x-example": false + }, + "transformations": { + "type": "boolean", + "description": "Image transformations are enabled.", + "x-example": false } }, "required": [ @@ -42217,7 +42236,8 @@ "allowedFileExtensions", "compression", "encryption", - "antivirus" + "antivirus", + "transformations" ], "example": { "$id": "5e5ea5c16897e", @@ -42236,7 +42256,8 @@ ], "compression": "gzip", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } }, "resourceToken": { From 39c5b6c4d0a6adff6fe0f2cecdcd3aeeb0e37666 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 09:53:55 +0530 Subject: [PATCH 150/167] regenerate sdk examples --- .../1.8.x/client-flutter/examples/avatars/get-browser.md | 2 +- .../1.8.x/client-flutter/examples/avatars/get-credit-card.md | 2 +- .../1.8.x/client-flutter/examples/avatars/get-favicon.md | 2 +- .../1.8.x/client-flutter/examples/avatars/get-flag.md | 2 +- .../1.8.x/client-flutter/examples/avatars/get-image.md | 2 +- .../1.8.x/client-flutter/examples/avatars/get-initials.md | 2 +- .../examples/1.8.x/client-flutter/examples/avatars/get-qr.md | 2 +- .../1.8.x/client-flutter/examples/avatars/get-screenshot.md | 2 +- .../client-flutter/examples/storage/get-file-download.md | 2 +- .../client-flutter/examples/storage/get-file-preview.md | 2 +- .../1.8.x/client-flutter/examples/storage/get-file-view.md | 2 +- .../examples/functions/create-template-deployment.md | 3 ++- .../console-cli/examples/sites/create-template-deployment.md | 3 ++- .../examples/functions/create-template-deployment.md | 5 +++-- .../console-web/examples/sites/create-template-deployment.md | 5 +++-- .../1.8.x/console-web/examples/storage/create-bucket.md | 3 ++- .../1.8.x/console-web/examples/storage/update-bucket.md | 3 ++- .../1.8.x/server-dart/examples/avatars/get-browser.md | 2 +- .../1.8.x/server-dart/examples/avatars/get-credit-card.md | 2 +- .../1.8.x/server-dart/examples/avatars/get-favicon.md | 2 +- docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md | 2 +- .../examples/1.8.x/server-dart/examples/avatars/get-image.md | 2 +- .../1.8.x/server-dart/examples/avatars/get-initials.md | 2 +- docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md | 2 +- .../1.8.x/server-dart/examples/avatars/get-screenshot.md | 2 +- .../examples/functions/create-template-deployment.md | 3 ++- .../examples/functions/get-deployment-download.md | 2 +- .../server-dart/examples/sites/create-template-deployment.md | 3 ++- .../server-dart/examples/sites/get-deployment-download.md | 2 +- .../1.8.x/server-dart/examples/storage/create-bucket.md | 1 + .../1.8.x/server-dart/examples/storage/get-file-download.md | 2 +- .../1.8.x/server-dart/examples/storage/get-file-preview.md | 2 +- .../1.8.x/server-dart/examples/storage/get-file-view.md | 2 +- .../1.8.x/server-dart/examples/storage/update-bucket.md | 1 + .../examples/functions/create-template-deployment.md | 4 +++- .../examples/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-dotnet/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-dotnet/examples/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 3 ++- .../server-go/examples/sites/create-template-deployment.md | 3 ++- .../1.8.x/server-go/examples/storage/create-bucket.md | 1 + .../1.8.x/server-go/examples/storage/update-bucket.md | 1 + .../examples/functions/create-template-deployment.md | 3 ++- .../examples/sites/create-template-deployment.md | 3 ++- .../1.8.x/server-graphql/examples/storage/create-bucket.md | 4 +++- .../1.8.x/server-graphql/examples/storage/update-bucket.md | 4 +++- .../java/functions/create-template-deployment.md | 4 +++- .../server-kotlin/java/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-kotlin/java/storage/create-bucket.md | 1 + .../1.8.x/server-kotlin/java/storage/update-bucket.md | 1 + .../kotlin/functions/create-template-deployment.md | 4 +++- .../server-kotlin/kotlin/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-kotlin/kotlin/storage/create-bucket.md | 3 ++- .../1.8.x/server-kotlin/kotlin/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 3 ++- .../examples/sites/create-template-deployment.md | 3 ++- .../1.8.x/server-nodejs/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-nodejs/examples/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 4 +++- .../server-php/examples/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-php/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-php/examples/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 4 +++- .../examples/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-python/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-python/examples/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 3 ++- .../server-rest/examples/sites/create-template-deployment.md | 3 ++- .../1.8.x/server-rest/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-rest/examples/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 4 +++- .../server-ruby/examples/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-ruby/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-ruby/examples/storage/update-bucket.md | 3 ++- .../examples/functions/create-template-deployment.md | 4 +++- .../examples/sites/create-template-deployment.md | 4 +++- .../1.8.x/server-swift/examples/storage/create-bucket.md | 3 ++- .../1.8.x/server-swift/examples/storage/update-bucket.md | 3 ++- 78 files changed, 144 insertions(+), 74 deletions(-) diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md index e97d24ab4f..50c28ff378 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getBrowser( +Uint8List bytes = await avatars.getBrowser( code: Browser.avantBrowser, width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md index 9ec42588b4..c3471fc2e8 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getCreditCard( +Uint8List bytes = await avatars.getCreditCard( code: CreditCard.americanExpress, width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md index 0df5ed0d2a..abd61a0974 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getFavicon( +Uint8List bytes = await avatars.getFavicon( url: 'https://example.com', ) diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md index 99d43409a0..e5a4c60ba9 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getFlag( +Uint8List bytes = await avatars.getFlag( code: Flag.afghanistan, width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md index 5b9d1b58c1..bbfcc03885 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getImage( +Uint8List bytes = await avatars.getImage( url: 'https://example.com', width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md index 0c5b62a309..29940c17bf 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getInitials( +Uint8List bytes = await avatars.getInitials( name: '<NAME>', // optional width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md index d9a533c886..0a75a6682f 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getQR( +Uint8List bytes = await avatars.getQR( text: '<TEXT>', size: 1, // optional margin: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md index 768cb8f271..f8cb6cfbcc 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getScreenshot( +Uint8List bytes = await avatars.getScreenshot( url: 'https://example.com', headers: {}, // optional viewportWidth: 1, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md index 5bef06ee7d..2cdba9b1fa 100644 --- a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md +++ b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); // Downloading file -UInt8List bytes = await storage.getFileDownload( +Uint8List bytes = await storage.getFileDownload( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md index 96338bd25a..6fd148e935 100644 --- a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); // Downloading file -UInt8List bytes = await storage.getFilePreview( +Uint8List bytes = await storage.getFilePreview( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', width: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md index 6587f086bd..bcf5902c4e 100644 --- a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md +++ b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); // Downloading file -UInt8List bytes = await storage.getFileView( +Uint8List bytes = await storage.getFileView( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // optional diff --git a/docs/examples/1.8.x/console-cli/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/console-cli/examples/functions/create-template-deployment.md index f3c8487cf7..72fa62b3c4 100644 --- a/docs/examples/1.8.x/console-cli/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/console-cli/examples/functions/create-template-deployment.md @@ -3,4 +3,5 @@ appwrite functions create-template-deployment \ --repository <REPOSITORY> \ --owner <OWNER> \ --root-directory <ROOT_DIRECTORY> \ - --version <VERSION> + --type commit \ + --reference <REFERENCE> diff --git a/docs/examples/1.8.x/console-cli/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/console-cli/examples/sites/create-template-deployment.md index 2eece41976..5242534073 100644 --- a/docs/examples/1.8.x/console-cli/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/console-cli/examples/sites/create-template-deployment.md @@ -3,4 +3,5 @@ appwrite sites create-template-deployment \ --repository <REPOSITORY> \ --owner <OWNER> \ --root-directory <ROOT_DIRECTORY> \ - --version <VERSION> + --type branch \ + --reference <REFERENCE> diff --git a/docs/examples/1.8.x/console-web/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/console-web/examples/functions/create-template-deployment.md index 8820ba3565..5bf812c1bc 100644 --- a/docs/examples/1.8.x/console-web/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/console-web/examples/functions/create-template-deployment.md @@ -1,4 +1,4 @@ -import { Client, Functions } from "@appwrite.io/console"; +import { Client, Functions, } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -11,7 +11,8 @@ const result = await functions.createTemplateDeployment({ repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: .Commit, + reference: '<REFERENCE>', activate: false // optional }); diff --git a/docs/examples/1.8.x/console-web/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/console-web/examples/sites/create-template-deployment.md index 969a0b855c..4f1d0184f7 100644 --- a/docs/examples/1.8.x/console-web/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/console-web/examples/sites/create-template-deployment.md @@ -1,4 +1,4 @@ -import { Client, Sites } from "@appwrite.io/console"; +import { Client, Sites, } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -11,7 +11,8 @@ const result = await sites.createTemplateDeployment({ repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: .Branch, + reference: '<REFERENCE>', activate: false // optional }); diff --git a/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md b/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md index 343568a408..4fd742bd32 100644 --- a/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md @@ -16,7 +16,8 @@ const result = await storage.createBucket({ allowedFileExtensions: [], // optional compression: .None, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional }); console.log(result); diff --git a/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md b/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md index b2c2eaa885..6914c374c9 100644 --- a/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md @@ -16,7 +16,8 @@ const result = await storage.updateBucket({ allowedFileExtensions: [], // optional compression: .None, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional }); console.log(result); diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md index 8d5287511d..1f326e8066 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getBrowser( +Uint8List result = await avatars.getBrowser( code: Browser.avantBrowser, width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md index 88fe35ebd9..8232d7b2b9 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getCreditCard( +Uint8List result = await avatars.getCreditCard( code: CreditCard.americanExpress, width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md index d4cd8eae83..e2df21f6fd 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md @@ -7,6 +7,6 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getFavicon( +Uint8List result = await avatars.getFavicon( url: 'https://example.com', ); diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md index 56046681bc..0aea028e5b 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getFlag( +Uint8List result = await avatars.getFlag( code: Flag.afghanistan, width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md index b6db1858c5..fc727f481e 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getImage( +Uint8List result = await avatars.getImage( url: 'https://example.com', width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md index 7dc0989b4d..be77c67147 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getInitials( +Uint8List result = await avatars.getInitials( name: '<NAME>', // (optional) width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md index f64fe8a4ff..f44ce59076 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getQR( +Uint8List result = await avatars.getQR( text: '<TEXT>', size: 1, // (optional) margin: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md index 7630648f98..0af7edafbf 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getScreenshot( +Uint8List result = await avatars.getScreenshot( url: 'https://example.com', headers: {}, // (optional) viewportWidth: 1, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-dart/examples/functions/create-template-deployment.md index cc293b0c3b..bfd94b1963 100644 --- a/docs/examples/1.8.x/server-dart/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-dart/examples/functions/create-template-deployment.md @@ -12,6 +12,7 @@ Deployment result = await functions.createTemplateDeployment( repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: .commit, + reference: '<REFERENCE>', activate: false, // (optional) ); diff --git a/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md b/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md index e7bbacf344..1b93e3bad9 100644 --- a/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md @@ -7,7 +7,7 @@ Client client = Client() Functions functions = Functions(client); -UInt8List result = await functions.getDeploymentDownload( +Uint8List result = await functions.getDeploymentDownload( functionId: '<FUNCTION_ID>', deploymentId: '<DEPLOYMENT_ID>', type: DeploymentDownloadType.source, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-dart/examples/sites/create-template-deployment.md index 348b4652b6..93c9b1d283 100644 --- a/docs/examples/1.8.x/server-dart/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-dart/examples/sites/create-template-deployment.md @@ -12,6 +12,7 @@ Deployment result = await sites.createTemplateDeployment( repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: .branch, + reference: '<REFERENCE>', activate: false, // (optional) ); diff --git a/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md b/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md index ad21070b8a..f6bbb3c35d 100644 --- a/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md @@ -7,7 +7,7 @@ Client client = Client() Sites sites = Sites(client); -UInt8List result = await sites.getDeploymentDownload( +Uint8List result = await sites.getDeploymentDownload( siteId: '<SITE_ID>', deploymentId: '<DEPLOYMENT_ID>', type: DeploymentDownloadType.source, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md index 79357d0e4a..7907b93297 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md @@ -20,4 +20,5 @@ Bucket result = await storage.createBucket( compression: .none, // (optional) encryption: false, // (optional) antivirus: false, // (optional) + transformations: false, // (optional) ); diff --git a/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md b/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md index 8c119c386c..34f40685fe 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); -UInt8List result = await storage.getFileDownload( +Uint8List result = await storage.getFileDownload( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md b/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md index a1f3c09b33..a14e12c630 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); -UInt8List result = await storage.getFilePreview( +Uint8List result = await storage.getFilePreview( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', width: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md b/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md index d48b51c19c..a1d9271f13 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); -UInt8List result = await storage.getFileView( +Uint8List result = await storage.getFileView( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md index f3eea941a3..83d0a16380 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md @@ -20,4 +20,5 @@ Bucket result = await storage.updateBucket( compression: .none, // (optional) encryption: false, // (optional) antivirus: false, // (optional) + transformations: false, // (optional) ); diff --git a/docs/examples/1.8.x/server-dotnet/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-dotnet/examples/functions/create-template-deployment.md index 019a9bf256..125eeda5cc 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-dotnet/examples/functions/create-template-deployment.md @@ -1,4 +1,5 @@ using Appwrite; +using Appwrite.Enums; using Appwrite.Models; using Appwrite.Services; @@ -14,6 +15,7 @@ Deployment result = await functions.CreateTemplateDeployment( repository: "<REPOSITORY>", owner: "<OWNER>", rootDirectory: "<ROOT_DIRECTORY>", - version: "<VERSION>", + type: .Commit, + reference: "<REFERENCE>", activate: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-dotnet/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-dotnet/examples/sites/create-template-deployment.md index 57f9a83d9c..9775cb659f 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-dotnet/examples/sites/create-template-deployment.md @@ -1,4 +1,5 @@ using Appwrite; +using Appwrite.Enums; using Appwrite.Models; using Appwrite.Services; @@ -14,6 +15,7 @@ Deployment result = await sites.CreateTemplateDeployment( repository: "<REPOSITORY>", owner: "<OWNER>", rootDirectory: "<ROOT_DIRECTORY>", - version: "<VERSION>", + type: .Branch, + reference: "<REFERENCE>", activate: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md index f009f694ad..8a13ad7093 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md @@ -20,5 +20,6 @@ Bucket result = await storage.CreateBucket( allowedFileExtensions: new List<string>(), // optional compression: .None, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md index d41a45961c..dd02eb771d 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md @@ -20,5 +20,6 @@ Bucket result = await storage.UpdateBucket( allowedFileExtensions: new List<string>(), // optional compression: .None, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-go/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-go/examples/functions/create-template-deployment.md index 14f694ba4a..df9591f461 100644 --- a/docs/examples/1.8.x/server-go/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-go/examples/functions/create-template-deployment.md @@ -19,6 +19,7 @@ response, error := service.CreateTemplateDeployment( "<REPOSITORY>", "<OWNER>", "<ROOT_DIRECTORY>", - "<VERSION>", + "commit", + "<REFERENCE>", functions.WithCreateTemplateDeploymentActivate(false), ) diff --git a/docs/examples/1.8.x/server-go/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-go/examples/sites/create-template-deployment.md index 483d3e79ff..85bf2a3cf6 100644 --- a/docs/examples/1.8.x/server-go/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-go/examples/sites/create-template-deployment.md @@ -19,6 +19,7 @@ response, error := service.CreateTemplateDeployment( "<REPOSITORY>", "<OWNER>", "<ROOT_DIRECTORY>", - "<VERSION>", + "branch", + "<REFERENCE>", sites.WithCreateTemplateDeploymentActivate(false), ) diff --git a/docs/examples/1.8.x/server-go/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-go/examples/storage/create-bucket.md index 64e3c40191..7bec2acb68 100644 --- a/docs/examples/1.8.x/server-go/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-go/examples/storage/create-bucket.md @@ -25,4 +25,5 @@ response, error := service.CreateBucket( storage.WithCreateBucketCompression("none"), storage.WithCreateBucketEncryption(false), storage.WithCreateBucketAntivirus(false), + storage.WithCreateBucketTransformations(false), ) diff --git a/docs/examples/1.8.x/server-go/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-go/examples/storage/update-bucket.md index bb5f7aa76d..7092c688b1 100644 --- a/docs/examples/1.8.x/server-go/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-go/examples/storage/update-bucket.md @@ -25,4 +25,5 @@ response, error := service.UpdateBucket( storage.WithUpdateBucketCompression("none"), storage.WithUpdateBucketEncryption(false), storage.WithUpdateBucketAntivirus(false), + storage.WithUpdateBucketTransformations(false), ) diff --git a/docs/examples/1.8.x/server-graphql/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-graphql/examples/functions/create-template-deployment.md index 0ce968e5f4..9b0da7ec47 100644 --- a/docs/examples/1.8.x/server-graphql/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-graphql/examples/functions/create-template-deployment.md @@ -4,7 +4,8 @@ mutation { repository: "<REPOSITORY>", owner: "<OWNER>", rootDirectory: "<ROOT_DIRECTORY>", - version: "<VERSION>", + type: "commit", + reference: "<REFERENCE>", activate: false ) { _id diff --git a/docs/examples/1.8.x/server-graphql/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-graphql/examples/sites/create-template-deployment.md index f63d8c5e5a..f528811cc3 100644 --- a/docs/examples/1.8.x/server-graphql/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-graphql/examples/sites/create-template-deployment.md @@ -4,7 +4,8 @@ mutation { repository: "<REPOSITORY>", owner: "<OWNER>", rootDirectory: "<ROOT_DIRECTORY>", - version: "<VERSION>", + type: "branch", + reference: "<REFERENCE>", activate: false ) { _id diff --git a/docs/examples/1.8.x/server-graphql/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-graphql/examples/storage/create-bucket.md index 45d03802d2..fe54321f90 100644 --- a/docs/examples/1.8.x/server-graphql/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-graphql/examples/storage/create-bucket.md @@ -9,7 +9,8 @@ mutation { allowedFileExtensions: [], compression: "none", encryption: false, - antivirus: false + antivirus: false, + transformations: false ) { _id _createdAt @@ -23,5 +24,6 @@ mutation { compression encryption antivirus + transformations } } diff --git a/docs/examples/1.8.x/server-graphql/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-graphql/examples/storage/update-bucket.md index 8265a15a58..ab4dc776fa 100644 --- a/docs/examples/1.8.x/server-graphql/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-graphql/examples/storage/update-bucket.md @@ -9,7 +9,8 @@ mutation { allowedFileExtensions: [], compression: "none", encryption: false, - antivirus: false + antivirus: false, + transformations: false ) { _id _createdAt @@ -23,5 +24,6 @@ mutation { compression encryption antivirus + transformations } } diff --git a/docs/examples/1.8.x/server-kotlin/java/functions/create-template-deployment.md b/docs/examples/1.8.x/server-kotlin/java/functions/create-template-deployment.md index 53b5a9ae6a..9a0642b04e 100644 --- a/docs/examples/1.8.x/server-kotlin/java/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-kotlin/java/functions/create-template-deployment.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Functions; +import io.appwrite.enums.Type; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,7 +15,8 @@ functions.createTemplateDeployment( "<REPOSITORY>", // repository "<OWNER>", // owner "<ROOT_DIRECTORY>", // rootDirectory - "<VERSION>", // version + .COMMIT, // type + "<REFERENCE>", // reference false, // activate (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { diff --git a/docs/examples/1.8.x/server-kotlin/java/sites/create-template-deployment.md b/docs/examples/1.8.x/server-kotlin/java/sites/create-template-deployment.md index 63aba4a067..a501461a2c 100644 --- a/docs/examples/1.8.x/server-kotlin/java/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-kotlin/java/sites/create-template-deployment.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Sites; +import io.appwrite.enums.Type; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,7 +15,8 @@ sites.createTemplateDeployment( "<REPOSITORY>", // repository "<OWNER>", // owner "<ROOT_DIRECTORY>", // rootDirectory - "<VERSION>", // version + .BRANCH, // type + "<REFERENCE>", // reference false, // activate (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { diff --git a/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md b/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md index d48db24094..248fd8d739 100644 --- a/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md @@ -22,6 +22,7 @@ storage.createBucket( .NONE, // compression (optional) false, // encryption (optional) false, // antivirus (optional) + false, // transformations (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md b/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md index 586b113578..866c7548a8 100644 --- a/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md @@ -22,6 +22,7 @@ storage.updateBucket( .NONE, // compression (optional) false, // encryption (optional) false, // antivirus (optional) + false, // transformations (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-template-deployment.md b/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-template-deployment.md index 90c311ec7a..b8eb44b4fa 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-template-deployment.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Functions +import io.appwrite.enums.Type val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,6 +15,7 @@ val response = functions.createTemplateDeployment( repository = "<REPOSITORY>", owner = "<OWNER>", rootDirectory = "<ROOT_DIRECTORY>", - version = "<VERSION>", + type = .COMMIT, + reference = "<REFERENCE>", activate = false // optional ) diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/sites/create-template-deployment.md b/docs/examples/1.8.x/server-kotlin/kotlin/sites/create-template-deployment.md index bf246be089..1f3d7d386a 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/sites/create-template-deployment.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Sites +import io.appwrite.enums.Type val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,6 +15,7 @@ val response = sites.createTemplateDeployment( repository = "<REPOSITORY>", owner = "<OWNER>", rootDirectory = "<ROOT_DIRECTORY>", - version = "<VERSION>", + type = .BRANCH, + reference = "<REFERENCE>", activate = false // optional ) diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md b/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md index 872932eeff..d89dca3b1f 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md @@ -21,5 +21,6 @@ val response = storage.createBucket( allowedFileExtensions = listOf(), // optional compression = "none", // optional encryption = false, // optional - antivirus = false // optional + antivirus = false, // optional + transformations = false // optional ) diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md b/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md index cb8187343e..f51fee9007 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md @@ -21,5 +21,6 @@ val response = storage.updateBucket( allowedFileExtensions = listOf(), // optional compression = "none", // optional encryption = false, // optional - antivirus = false // optional + antivirus = false, // optional + transformations = false // optional ) diff --git a/docs/examples/1.8.x/server-nodejs/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-nodejs/examples/functions/create-template-deployment.md index 8f6395f8fb..999c029f8f 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-nodejs/examples/functions/create-template-deployment.md @@ -12,6 +12,7 @@ const result = await functions.createTemplateDeployment({ repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: sdk..Commit, + reference: '<REFERENCE>', activate: false // optional }); diff --git a/docs/examples/1.8.x/server-nodejs/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-nodejs/examples/sites/create-template-deployment.md index 7dfb4370e6..dc9736fa80 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-nodejs/examples/sites/create-template-deployment.md @@ -12,6 +12,7 @@ const result = await sites.createTemplateDeployment({ repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: sdk..Branch, + reference: '<REFERENCE>', activate: false // optional }); diff --git a/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md index b47d2c8353..a279ab50ed 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md @@ -17,5 +17,6 @@ const result = await storage.createBucket({ allowedFileExtensions: [], // optional compression: sdk..None, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional }); diff --git a/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md index 9535914eeb..cf313c0a2b 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md @@ -17,5 +17,6 @@ const result = await storage.updateBucket({ allowedFileExtensions: [], // optional compression: sdk..None, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional }); diff --git a/docs/examples/1.8.x/server-php/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-php/examples/functions/create-template-deployment.md index 9d22bdc1b4..5888396312 100644 --- a/docs/examples/1.8.x/server-php/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-php/examples/functions/create-template-deployment.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Functions; +use Appwrite\Enums\Type; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -15,6 +16,7 @@ $result = $functions->createTemplateDeployment( repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: Type::COMMIT(), + reference: '<REFERENCE>', activate: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-php/examples/sites/create-template-deployment.md index f2d1f3cd8b..314ffdd1b9 100644 --- a/docs/examples/1.8.x/server-php/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-php/examples/sites/create-template-deployment.md @@ -2,6 +2,7 @@ use Appwrite\Client; use Appwrite\Services\Sites; +use Appwrite\Enums\Type; $client = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -15,6 +16,7 @@ $result = $sites->createTemplateDeployment( repository: '<REPOSITORY>', owner: '<OWNER>', rootDirectory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: Type::BRANCH(), + reference: '<REFERENCE>', activate: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md index 3d4f717e4d..31840957a2 100644 --- a/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-php/examples/storage/create-bucket.md @@ -23,5 +23,6 @@ $result = $storage->createBucket( allowedFileExtensions: [], // optional compression: Compression::NONE(), // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md index 77f4262c2d..1556257849 100644 --- a/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-php/examples/storage/update-bucket.md @@ -23,5 +23,6 @@ $result = $storage->updateBucket( allowedFileExtensions: [], // optional compression: Compression::NONE(), // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-python/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-python/examples/functions/create-template-deployment.md index 6083cc1cb3..d9f8f70a82 100644 --- a/docs/examples/1.8.x/server-python/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-python/examples/functions/create-template-deployment.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.functions import Functions +from appwrite.enums import client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,6 +14,7 @@ result = functions.create_template_deployment( repository = '<REPOSITORY>', owner = '<OWNER>', root_directory = '<ROOT_DIRECTORY>', - version = '<VERSION>', + type = .COMMIT, + reference = '<REFERENCE>', activate = False # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-python/examples/sites/create-template-deployment.md index ac05f9e663..fb47cb1453 100644 --- a/docs/examples/1.8.x/server-python/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-python/examples/sites/create-template-deployment.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.sites import Sites +from appwrite.enums import client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,6 +14,7 @@ result = sites.create_template_deployment( repository = '<REPOSITORY>', owner = '<OWNER>', root_directory = '<ROOT_DIRECTORY>', - version = '<VERSION>', + type = .BRANCH, + reference = '<REFERENCE>', activate = False # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md index e08b2d0d6b..61430416bc 100644 --- a/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md @@ -20,5 +20,6 @@ result = storage.create_bucket( allowed_file_extensions = [], # optional compression = .NONE, # optional encryption = False, # optional - antivirus = False # optional + antivirus = False, # optional + transformations = False # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md index bfa7cc3fdb..977ef58448 100644 --- a/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md @@ -20,5 +20,6 @@ result = storage.update_bucket( allowed_file_extensions = [], # optional compression = .NONE, # optional encryption = False, # optional - antivirus = False # optional + antivirus = False, # optional + transformations = False # optional ) diff --git a/docs/examples/1.8.x/server-rest/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-rest/examples/functions/create-template-deployment.md index 18ebf65efe..474763831f 100644 --- a/docs/examples/1.8.x/server-rest/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-rest/examples/functions/create-template-deployment.md @@ -9,6 +9,7 @@ X-Appwrite-Key: <YOUR_API_KEY> "repository": "<REPOSITORY>", "owner": "<OWNER>", "rootDirectory": "<ROOT_DIRECTORY>", - "version": "<VERSION>", + "type": "commit", + "reference": "<REFERENCE>", "activate": false } diff --git a/docs/examples/1.8.x/server-rest/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-rest/examples/sites/create-template-deployment.md index 3b21f4f754..9f58d3e97e 100644 --- a/docs/examples/1.8.x/server-rest/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-rest/examples/sites/create-template-deployment.md @@ -9,6 +9,7 @@ X-Appwrite-Key: <YOUR_API_KEY> "repository": "<REPOSITORY>", "owner": "<OWNER>", "rootDirectory": "<ROOT_DIRECTORY>", - "version": "<VERSION>", + "type": "branch", + "reference": "<REFERENCE>", "activate": false } diff --git a/docs/examples/1.8.x/server-rest/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-rest/examples/storage/create-bucket.md index 59f1c4f403..81104d36f5 100644 --- a/docs/examples/1.8.x/server-rest/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-rest/examples/storage/create-bucket.md @@ -15,5 +15,6 @@ X-Appwrite-Key: <YOUR_API_KEY> "allowedFileExtensions": [], "compression": "none", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } diff --git a/docs/examples/1.8.x/server-rest/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-rest/examples/storage/update-bucket.md index 0f966da0b5..d46ce52a58 100644 --- a/docs/examples/1.8.x/server-rest/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-rest/examples/storage/update-bucket.md @@ -14,5 +14,6 @@ X-Appwrite-Key: <YOUR_API_KEY> "allowedFileExtensions": [], "compression": "none", "encryption": false, - "antivirus": false + "antivirus": false, + "transformations": false } diff --git a/docs/examples/1.8.x/server-ruby/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-ruby/examples/functions/create-template-deployment.md index a447b6e9aa..cfe0adc263 100644 --- a/docs/examples/1.8.x/server-ruby/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-ruby/examples/functions/create-template-deployment.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -14,6 +15,7 @@ result = functions.create_template_deployment( repository: '<REPOSITORY>', owner: '<OWNER>', root_directory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: ::COMMIT, + reference: '<REFERENCE>', activate: false # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-ruby/examples/sites/create-template-deployment.md index 7df9665590..9e1cc93986 100644 --- a/docs/examples/1.8.x/server-ruby/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-ruby/examples/sites/create-template-deployment.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -14,6 +15,7 @@ result = sites.create_template_deployment( repository: '<REPOSITORY>', owner: '<OWNER>', root_directory: '<ROOT_DIRECTORY>', - version: '<VERSION>', + type: ::BRANCH, + reference: '<REFERENCE>', activate: false # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md index 4a12518fb7..d10e7b8127 100644 --- a/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md @@ -21,5 +21,6 @@ result = storage.create_bucket( allowed_file_extensions: [], # optional compression: ::NONE, # optional encryption: false, # optional - antivirus: false # optional + antivirus: false, # optional + transformations: false # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md index 2e44aad536..dbb491df5a 100644 --- a/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md @@ -21,5 +21,6 @@ result = storage.update_bucket( allowed_file_extensions: [], # optional compression: ::NONE, # optional encryption: false, # optional - antivirus: false # optional + antivirus: false, # optional + transformations: false # optional ) diff --git a/docs/examples/1.8.x/server-swift/examples/functions/create-template-deployment.md b/docs/examples/1.8.x/server-swift/examples/functions/create-template-deployment.md index 27c5311c7a..6a9045637c 100644 --- a/docs/examples/1.8.x/server-swift/examples/functions/create-template-deployment.md +++ b/docs/examples/1.8.x/server-swift/examples/functions/create-template-deployment.md @@ -1,4 +1,5 @@ import Appwrite +import AppwriteEnums let client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -12,7 +13,8 @@ let deployment = try await functions.createTemplateDeployment( repository: "<REPOSITORY>", owner: "<OWNER>", rootDirectory: "<ROOT_DIRECTORY>", - version: "<VERSION>", + type: .commit, + reference: "<REFERENCE>", activate: false // optional ) diff --git a/docs/examples/1.8.x/server-swift/examples/sites/create-template-deployment.md b/docs/examples/1.8.x/server-swift/examples/sites/create-template-deployment.md index 1cb3e42030..250eb124a5 100644 --- a/docs/examples/1.8.x/server-swift/examples/sites/create-template-deployment.md +++ b/docs/examples/1.8.x/server-swift/examples/sites/create-template-deployment.md @@ -1,4 +1,5 @@ import Appwrite +import AppwriteEnums let client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -12,7 +13,8 @@ let deployment = try await sites.createTemplateDeployment( repository: "<REPOSITORY>", owner: "<OWNER>", rootDirectory: "<ROOT_DIRECTORY>", - version: "<VERSION>", + type: .branch, + reference: "<REFERENCE>", activate: false // optional ) diff --git a/docs/examples/1.8.x/server-swift/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-swift/examples/storage/create-bucket.md index a97f450bfe..9931b81943 100644 --- a/docs/examples/1.8.x/server-swift/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-swift/examples/storage/create-bucket.md @@ -18,6 +18,7 @@ let bucket = try await storage.createBucket( allowedFileExtensions: [], // optional compression: .none, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional ) diff --git a/docs/examples/1.8.x/server-swift/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-swift/examples/storage/update-bucket.md index 2d89d7c464..be283b7d6a 100644 --- a/docs/examples/1.8.x/server-swift/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-swift/examples/storage/update-bucket.md @@ -18,6 +18,7 @@ let bucket = try await storage.updateBucket( allowedFileExtensions: [], // optional compression: .none, // optional encryption: false, // optional - antivirus: false // optional + antivirus: false, // optional + transformations: false // optional ) From b6fbddad81aa644f5dff511698d0759395d78870 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 11:07:50 +0530 Subject: [PATCH 151/167] fix: a lot of enum examples generated --- composer.json | 2 +- composer.lock | 32 ++++++++++--------- .../java/avatars/get-screenshot.md | 9 ++++-- .../java/functions/create-execution.md | 1 + .../java/storage/get-file-preview.md | 2 ++ .../kotlin/avatars/get-screenshot.md | 3 ++ .../kotlin/functions/create-execution.md | 1 + .../kotlin/storage/get-file-preview.md | 2 ++ .../examples/avatars/get-browser.md | 2 +- .../examples/avatars/get-credit-card.md | 2 +- .../examples/avatars/get-favicon.md | 2 +- .../examples/avatars/get-flag.md | 2 +- .../examples/avatars/get-image.md | 2 +- .../examples/avatars/get-initials.md | 2 +- .../client-flutter/examples/avatars/get-qr.md | 2 +- .../examples/avatars/get-screenshot.md | 14 ++++---- .../examples/storage/get-file-download.md | 2 +- .../examples/storage/get-file-preview.md | 2 +- .../examples/storage/get-file-view.md | 2 +- .../examples/avatars/get-screenshot.md | 8 ++--- .../examples/avatars/get-screenshot.md | 8 ++--- .../examples/avatars/get-screenshot.md | 8 ++--- .../console-web/examples/functions/create.md | 4 +-- .../console-web/examples/functions/update.md | 4 +-- .../examples/health/get-failed-jobs.md | 4 +-- .../console-web/examples/projects/create.md | 4 +-- .../examples/projects/update-api-status.md | 4 +-- .../examples/proxy/create-redirect-rule.md | 4 +-- .../console-web/examples/sites/create.md | 8 ++--- .../console-web/examples/sites/update.md | 8 ++--- .../examples/storage/create-bucket.md | 4 +-- .../examples/storage/update-bucket.md | 4 +-- .../examples/avatars/get-browser.md | 2 +- .../examples/avatars/get-credit-card.md | 2 +- .../examples/avatars/get-favicon.md | 2 +- .../server-dart/examples/avatars/get-flag.md | 2 +- .../server-dart/examples/avatars/get-image.md | 2 +- .../examples/avatars/get-initials.md | 2 +- .../server-dart/examples/avatars/get-qr.md | 2 +- .../examples/avatars/get-screenshot.md | 8 ++--- .../server-dart/examples/functions/create.md | 2 +- .../functions/get-deployment-download.md | 2 +- .../server-dart/examples/functions/update.md | 2 +- .../examples/health/get-failed-jobs.md | 2 +- .../server-dart/examples/sites/create.md | 6 ++-- .../examples/sites/get-deployment-download.md | 2 +- .../server-dart/examples/sites/update.md | 6 ++-- .../examples/storage/create-bucket.md | 2 +- .../examples/storage/get-file-download.md | 2 +- .../examples/storage/get-file-preview.md | 2 +- .../examples/storage/get-file-view.md | 2 +- .../examples/storage/update-bucket.md | 2 +- .../examples/avatars/get-screenshot.md | 6 ++-- .../examples/functions/create.md | 2 +- .../examples/functions/update.md | 2 +- .../examples/health/get-failed-jobs.md | 2 +- .../server-dotnet/examples/sites/create.md | 6 ++-- .../server-dotnet/examples/sites/update.md | 6 ++-- .../examples/storage/create-bucket.md | 2 +- .../examples/storage/update-bucket.md | 2 +- .../java/avatars/get-screenshot.md | 9 ++++-- .../create-relationship-attribute.md | 1 + .../update-relationship-attribute.md | 1 + .../java/functions/create-execution.md | 1 + .../server-kotlin/java/functions/create.md | 2 +- .../java/functions/get-deployment-download.md | 1 + .../server-kotlin/java/functions/update.md | 3 +- .../java/health/get-failed-jobs.md | 2 +- .../java/messaging/create-push.md | 1 + .../java/messaging/create-smtp-provider.md | 1 + .../java/messaging/update-push.md | 1 + .../java/messaging/update-smtp-provider.md | 1 + .../1.8.x/server-kotlin/java/sites/create.md | 7 ++-- .../java/sites/get-deployment-download.md | 1 + .../1.8.x/server-kotlin/java/sites/update.md | 8 +++-- .../java/storage/create-bucket.md | 3 +- .../java/storage/get-file-preview.md | 2 ++ .../java/storage/update-bucket.md | 3 +- .../tablesdb/create-relationship-column.md | 1 + .../tablesdb/update-relationship-column.md | 1 + .../java/users/create-sha-user.md | 1 + .../kotlin/avatars/get-screenshot.md | 3 ++ .../create-relationship-attribute.md | 1 + .../update-relationship-attribute.md | 1 + .../kotlin/functions/create-execution.md | 1 + .../server-kotlin/kotlin/functions/create.md | 2 +- .../functions/get-deployment-download.md | 1 + .../server-kotlin/kotlin/functions/update.md | 1 + .../kotlin/health/get-failed-jobs.md | 2 +- .../kotlin/messaging/create-push.md | 1 + .../kotlin/messaging/create-smtp-provider.md | 1 + .../kotlin/messaging/update-push.md | 1 + .../kotlin/messaging/update-smtp-provider.md | 1 + .../server-kotlin/kotlin/sites/create.md | 5 +-- .../kotlin/sites/get-deployment-download.md | 1 + .../server-kotlin/kotlin/sites/update.md | 4 ++- .../kotlin/storage/create-bucket.md | 1 + .../kotlin/storage/get-file-preview.md | 2 ++ .../kotlin/storage/update-bucket.md | 1 + .../tablesdb/create-relationship-column.md | 1 + .../tablesdb/update-relationship-column.md | 1 + .../kotlin/users/create-sha-user.md | 1 + .../examples/avatars/get-screenshot.md | 6 ++-- .../examples/functions/create.md | 2 +- .../examples/functions/update.md | 2 +- .../examples/health/get-failed-jobs.md | 2 +- .../server-nodejs/examples/sites/create.md | 6 ++-- .../server-nodejs/examples/sites/update.md | 6 ++-- .../examples/storage/create-bucket.md | 2 +- .../examples/storage/update-bucket.md | 2 +- .../examples/avatars/get-screenshot.md | 9 ++++-- .../create-relationship-attribute.md | 1 + .../update-relationship-attribute.md | 1 + .../examples/functions/create-execution.md | 1 + .../examples/functions/create.md | 4 +-- .../functions/get-deployment-download.md | 1 + .../examples/functions/update.md | 3 +- .../examples/health/get-failed-jobs.md | 4 +-- .../examples/messaging/create-push.md | 1 + .../messaging/create-smtp-provider.md | 1 + .../examples/messaging/update-push.md | 1 + .../messaging/update-smtp-provider.md | 1 + .../server-python/examples/sites/create.md | 11 ++++--- .../examples/sites/get-deployment-download.md | 1 + .../server-python/examples/sites/update.md | 10 +++--- .../examples/storage/create-bucket.md | 3 +- .../examples/storage/get-file-preview.md | 2 ++ .../examples/storage/update-bucket.md | 3 +- .../tablesdb/create-relationship-column.md | 1 + .../tablesdb/update-relationship-column.md | 1 + .../examples/users/create-sha-user.md | 1 + .../examples/avatars/get-screenshot.md | 7 ++-- .../update-relationship-attribute.md | 1 + .../examples/functions/create-execution.md | 1 + .../server-ruby/examples/functions/create.md | 2 +- .../functions/get-deployment-download.md | 1 + .../server-ruby/examples/functions/update.md | 3 +- .../examples/health/get-failed-jobs.md | 2 +- .../examples/messaging/create-push.md | 1 + .../messaging/create-smtp-provider.md | 1 + .../examples/messaging/update-push.md | 1 + .../messaging/update-smtp-provider.md | 1 + .../server-ruby/examples/sites/create.md | 6 ++-- .../examples/sites/get-deployment-download.md | 1 + .../server-ruby/examples/sites/update.md | 6 ++-- .../examples/storage/create-bucket.md | 3 +- .../examples/storage/get-file-preview.md | 1 + .../examples/storage/update-bucket.md | 3 +- .../tablesdb/update-relationship-column.md | 1 + .../examples/users/create-sha-user.md | 1 + 150 files changed, 277 insertions(+), 179 deletions(-) diff --git a/composer.json b/composer.json index 1cff497d08..0a4e347d7f 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,7 @@ }, "require-dev": { "ext-fileinfo": "*", - "appwrite/sdk-generator": "*", + "appwrite/sdk-generator": "dev-fix-enum-rendering", "phpunit/phpunit": "9.*", "swoole/ide-helper": "5.1.2", "phpstan/phpstan": "1.8.*", diff --git a/composer.lock b/composer.lock index afbbaa516d..f173903669 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": "3b502f78f5e31f2ea7b4c69e3301283a", + "content-hash": "bc877cc8bf639e146710e0d7656adbec", "packages": [ { "name": "adhocore/jwt", @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.5", + "version": "dev-fix-enum-rendering", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "1f3686e41a2d10829220b74f54c80a770e9f968a" + "reference": "3f39061b0db19057219bab6352afa2201306eedf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1f3686e41a2d10829220b74f54c80a770e9f968a", - "reference": "1f3686e41a2d10829220b74f54c80a770e9f968a", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/3f39061b0db19057219bab6352afa2201306eedf", + "reference": "3f39061b0db19057219bab6352afa2201306eedf", "shasum": "" }, "require": { @@ -5428,9 +5428,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.5.5" + "source": "https://github.com/appwrite/sdk-generator/tree/fix-enum-rendering" }, - "time": "2025-11-14T05:56:33+00:00" + "time": "2025-11-18T05:35:14+00:00" }, { "name": "doctrine/annotations", @@ -8718,16 +8718,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", - "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -8756,7 +8756,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.3.0" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -8764,7 +8764,7 @@ "type": "github" } ], - "time": "2025-11-13T13:44:09+00:00" + "time": "2025-11-17T20:03:58+00:00" }, { "name": "twig/twig", @@ -8897,7 +8897,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "appwrite/sdk-generator": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8921,5 +8923,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md b/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md index 077716f523..48babdca20 100644 --- a/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/client-android/java/avatars/get-screenshot.md @@ -1,6 +1,9 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Avatars; +import io.appwrite.enums.Theme; +import io.appwrite.enums.Timezone; +import io.appwrite.enums.Output; Client client = new Client(context) .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,11 +17,11 @@ avatars.getScreenshot( 1, // viewportWidth (optional) 1, // viewportHeight (optional) 0.1, // scale (optional) - theme.LIGHT, // theme (optional) + Theme.LIGHT, // theme (optional) "<USER_AGENT>", // userAgent (optional) false, // fullpage (optional) "<LOCALE>", // locale (optional) - timezone.AFRICA_ABIDJAN, // timezone (optional) + Timezone.AFRICA_ABIDJAN, // timezone (optional) -90, // latitude (optional) -180, // longitude (optional) 0, // accuracy (optional) @@ -28,7 +31,7 @@ avatars.getScreenshot( 0, // width (optional) 0, // height (optional) -1, // quality (optional) - output.JPG, // output (optional) + Output.JPG, // output (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/1.8.x/client-android/java/functions/create-execution.md b/docs/examples/1.8.x/client-android/java/functions/create-execution.md index 06c50278a5..758881d13c 100644 --- a/docs/examples/1.8.x/client-android/java/functions/create-execution.md +++ b/docs/examples/1.8.x/client-android/java/functions/create-execution.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Functions; +import io.appwrite.enums.ExecutionMethod; Client client = new Client(context) .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/client-android/java/storage/get-file-preview.md b/docs/examples/1.8.x/client-android/java/storage/get-file-preview.md index 67b92ebf85..392ef11649 100644 --- a/docs/examples/1.8.x/client-android/java/storage/get-file-preview.md +++ b/docs/examples/1.8.x/client-android/java/storage/get-file-preview.md @@ -1,6 +1,8 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Storage; +import io.appwrite.enums.ImageGravity; +import io.appwrite.enums.ImageFormat; Client client = new Client(context) .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md b/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md index 014ca90fd8..2638e9e6a5 100644 --- a/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/client-android/kotlin/avatars/get-screenshot.md @@ -1,6 +1,9 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Avatars +import io.appwrite.enums.Theme +import io.appwrite.enums.Timezone +import io.appwrite.enums.Output val client = Client(context) .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/client-android/kotlin/functions/create-execution.md b/docs/examples/1.8.x/client-android/kotlin/functions/create-execution.md index 5e1950b8d9..8f7b49b849 100644 --- a/docs/examples/1.8.x/client-android/kotlin/functions/create-execution.md +++ b/docs/examples/1.8.x/client-android/kotlin/functions/create-execution.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Functions +import io.appwrite.enums.ExecutionMethod val client = Client(context) .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/client-android/kotlin/storage/get-file-preview.md b/docs/examples/1.8.x/client-android/kotlin/storage/get-file-preview.md index d766dc7174..a4841d53c4 100644 --- a/docs/examples/1.8.x/client-android/kotlin/storage/get-file-preview.md +++ b/docs/examples/1.8.x/client-android/kotlin/storage/get-file-preview.md @@ -1,6 +1,8 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Storage +import io.appwrite.enums.ImageGravity +import io.appwrite.enums.ImageFormat val client = Client(context) .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md index e97d24ab4f..50c28ff378 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-browser.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getBrowser( +Uint8List bytes = await avatars.getBrowser( code: Browser.avantBrowser, width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md index 9ec42588b4..c3471fc2e8 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-credit-card.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getCreditCard( +Uint8List bytes = await avatars.getCreditCard( code: CreditCard.americanExpress, width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md index 0df5ed0d2a..abd61a0974 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-favicon.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getFavicon( +Uint8List bytes = await avatars.getFavicon( url: 'https://example.com', ) diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md index 99d43409a0..e5a4c60ba9 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-flag.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getFlag( +Uint8List bytes = await avatars.getFlag( code: Flag.afghanistan, width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md index 5b9d1b58c1..bbfcc03885 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-image.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getImage( +Uint8List bytes = await avatars.getImage( url: 'https://example.com', width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md index 0c5b62a309..29940c17bf 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-initials.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getInitials( +Uint8List bytes = await avatars.getInitials( name: '<NAME>', // optional width: 0, // optional height: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md index d9a533c886..0a75a6682f 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-qr.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getQR( +Uint8List bytes = await avatars.getQR( text: '<TEXT>', size: 1, // optional margin: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md index 768cb8f271..42a5ca7230 100644 --- a/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/client-flutter/examples/avatars/get-screenshot.md @@ -7,17 +7,17 @@ Client client = Client() Avatars avatars = Avatars(client); // Downloading file -UInt8List bytes = await avatars.getScreenshot( +Uint8List bytes = await avatars.getScreenshot( url: 'https://example.com', headers: {}, // optional viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: .light, // optional + theme: Theme.light, // optional userAgent: '<USER_AGENT>', // optional fullpage: false, // optional locale: '<LOCALE>', // optional - timezone: .africaAbidjan, // optional + timezone: Timezone.africaAbidjan, // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -27,7 +27,7 @@ UInt8List bytes = await avatars.getScreenshot( width: 0, // optional height: 0, // optional quality: -1, // optional - output: .jpg, // optional + output: Output.jpg, // optional ) final file = File('path_to_file/filename.ext'); @@ -41,11 +41,11 @@ FutureBuilder( viewportWidth:1 , // optional viewportHeight:1 , // optional scale:0.1 , // optional - theme: .light, // optional + theme: Theme.light, // optional userAgent:'<USER_AGENT>' , // optional fullpage:false , // optional locale:'<LOCALE>' , // optional - timezone: .africaAbidjan, // optional + timezone: Timezone.africaAbidjan, // optional latitude:-90 , // optional longitude:-180 , // optional accuracy:0 , // optional @@ -55,7 +55,7 @@ FutureBuilder( width:0 , // optional height:0 , // optional quality:-1 , // optional - output: .jpg, // optional + output: Output.jpg, // optional ), // Works for both public file and private file, for private files you need to be logged in builder: (context, snapshot) { return snapshot.hasData && snapshot.data != null diff --git a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md index 5bef06ee7d..2cdba9b1fa 100644 --- a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md +++ b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-download.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); // Downloading file -UInt8List bytes = await storage.getFileDownload( +Uint8List bytes = await storage.getFileDownload( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md index 96338bd25a..6fd148e935 100644 --- a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-preview.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); // Downloading file -UInt8List bytes = await storage.getFilePreview( +Uint8List bytes = await storage.getFilePreview( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', width: 0, // optional diff --git a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md index 6587f086bd..bcf5902c4e 100644 --- a/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md +++ b/docs/examples/1.8.x/client-flutter/examples/storage/get-file-view.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); // Downloading file -UInt8List bytes = await storage.getFileView( +Uint8List bytes = await storage.getFileView( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // optional diff --git a/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md index 7482b4cf0e..918ab667d6 100644 --- a/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/client-react-native/examples/avatars/get-screenshot.md @@ -1,4 +1,4 @@ -import { Client, Avatars, , , } from "react-native-appwrite"; +import { Client, Avatars, Theme, Timezone, Output } from "react-native-appwrite"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -12,11 +12,11 @@ const result = avatars.getScreenshot({ viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: .Light, // optional + theme: Theme.Light, // optional userAgent: '<USER_AGENT>', // optional fullpage: false, // optional locale: '<LOCALE>', // optional - timezone: .AfricaAbidjan, // optional + timezone: Timezone.AfricaAbidjan, // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -26,7 +26,7 @@ const result = avatars.getScreenshot({ width: 0, // optional height: 0, // optional quality: -1, // optional - output: .Jpg // optional + output: Output.Jpg // optional }); console.log(result); diff --git a/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md index c4722be633..75d6bcf80c 100644 --- a/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/client-web/examples/avatars/get-screenshot.md @@ -1,4 +1,4 @@ -import { Client, Avatars, , , } from "appwrite"; +import { Client, Avatars, Theme, Timezone, Output } from "appwrite"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -12,11 +12,11 @@ const result = avatars.getScreenshot({ viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: .Light, // optional + theme: Theme.Light, // optional userAgent: '<USER_AGENT>', // optional fullpage: false, // optional locale: '<LOCALE>', // optional - timezone: .AfricaAbidjan, // optional + timezone: Timezone.AfricaAbidjan, // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -26,7 +26,7 @@ const result = avatars.getScreenshot({ width: 0, // optional height: 0, // optional quality: -1, // optional - output: .Jpg // optional + output: Output.Jpg // optional }); console.log(result); diff --git a/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md index 3a9437515d..25ccc040f0 100644 --- a/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/console-web/examples/avatars/get-screenshot.md @@ -1,4 +1,4 @@ -import { Client, Avatars, , , } from "@appwrite.io/console"; +import { Client, Avatars, Theme, Timezone, Output } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -12,11 +12,11 @@ const result = avatars.getScreenshot({ viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: .Light, // optional + theme: Theme.Light, // optional userAgent: '<USER_AGENT>', // optional fullpage: false, // optional locale: '<LOCALE>', // optional - timezone: .AfricaAbidjan, // optional + timezone: Timezone.AfricaAbidjan, // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -26,7 +26,7 @@ const result = avatars.getScreenshot({ width: 0, // optional height: 0, // optional quality: -1, // optional - output: .Jpg // optional + output: Output.Jpg // optional }); console.log(result); diff --git a/docs/examples/1.8.x/console-web/examples/functions/create.md b/docs/examples/1.8.x/console-web/examples/functions/create.md index b3ebbaf5a4..695d929daf 100644 --- a/docs/examples/1.8.x/console-web/examples/functions/create.md +++ b/docs/examples/1.8.x/console-web/examples/functions/create.md @@ -1,4 +1,4 @@ -import { Client, Functions, } from "@appwrite.io/console"; +import { Client, Functions, Runtime } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -9,7 +9,7 @@ const functions = new Functions(client); const result = await functions.create({ functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: .Node145, + runtime: Runtime.Node145, execute: ["any"], // optional events: [], // optional schedule: '', // optional diff --git a/docs/examples/1.8.x/console-web/examples/functions/update.md b/docs/examples/1.8.x/console-web/examples/functions/update.md index 377712bfb7..53fe85bf80 100644 --- a/docs/examples/1.8.x/console-web/examples/functions/update.md +++ b/docs/examples/1.8.x/console-web/examples/functions/update.md @@ -1,4 +1,4 @@ -import { Client, Functions, } from "@appwrite.io/console"; +import { Client, Functions, Runtime } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -9,7 +9,7 @@ const functions = new Functions(client); const result = await functions.update({ functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: .Node145, // optional + runtime: Runtime.Node145, // optional execute: ["any"], // optional events: [], // optional schedule: '', // optional diff --git a/docs/examples/1.8.x/console-web/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/console-web/examples/health/get-failed-jobs.md index d0bac0cd6f..f47927214f 100644 --- a/docs/examples/1.8.x/console-web/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/console-web/examples/health/get-failed-jobs.md @@ -1,4 +1,4 @@ -import { Client, Health, } from "@appwrite.io/console"; +import { Client, Health, Name } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -7,7 +7,7 @@ const client = new Client() const health = new Health(client); const result = await health.getFailedJobs({ - name: .V1Database, + name: Name.V1Database, threshold: null // optional }); diff --git a/docs/examples/1.8.x/console-web/examples/projects/create.md b/docs/examples/1.8.x/console-web/examples/projects/create.md index 44abc021ef..2bfcaa79bb 100644 --- a/docs/examples/1.8.x/console-web/examples/projects/create.md +++ b/docs/examples/1.8.x/console-web/examples/projects/create.md @@ -1,4 +1,4 @@ -import { Client, Projects, } from "@appwrite.io/console"; +import { Client, Projects, Region } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -10,7 +10,7 @@ const result = await projects.create({ projectId: '', name: '<NAME>', teamId: '<TEAM_ID>', - region: .Default, // optional + region: Region.Default, // optional description: '<DESCRIPTION>', // optional logo: '<LOGO>', // optional url: 'https://example.com', // optional diff --git a/docs/examples/1.8.x/console-web/examples/projects/update-api-status.md b/docs/examples/1.8.x/console-web/examples/projects/update-api-status.md index 7ec06fee58..7f0f7ca970 100644 --- a/docs/examples/1.8.x/console-web/examples/projects/update-api-status.md +++ b/docs/examples/1.8.x/console-web/examples/projects/update-api-status.md @@ -1,4 +1,4 @@ -import { Client, Projects, } from "@appwrite.io/console"; +import { Client, Projects, Api } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const projects = new Projects(client); const result = await projects.updateAPIStatus({ projectId: '<PROJECT_ID>', - api: .Rest, + api: Api.Rest, status: false }); diff --git a/docs/examples/1.8.x/console-web/examples/proxy/create-redirect-rule.md b/docs/examples/1.8.x/console-web/examples/proxy/create-redirect-rule.md index 396d6dee58..83a98438ec 100644 --- a/docs/examples/1.8.x/console-web/examples/proxy/create-redirect-rule.md +++ b/docs/examples/1.8.x/console-web/examples/proxy/create-redirect-rule.md @@ -1,4 +1,4 @@ -import { Client, Proxy, , ProxyResourceType } from "@appwrite.io/console"; +import { Client, Proxy, StatusCode, ProxyResourceType } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -9,7 +9,7 @@ const proxy = new Proxy(client); const result = await proxy.createRedirectRule({ domain: '', url: 'https://example.com', - statusCode: .MovedPermanently301, + statusCode: StatusCode.MovedPermanently301, resourceId: '<RESOURCE_ID>', resourceType: ProxyResourceType.Site }); diff --git a/docs/examples/1.8.x/console-web/examples/sites/create.md b/docs/examples/1.8.x/console-web/examples/sites/create.md index bd4e2d1f08..e59139a1e2 100644 --- a/docs/examples/1.8.x/console-web/examples/sites/create.md +++ b/docs/examples/1.8.x/console-web/examples/sites/create.md @@ -1,4 +1,4 @@ -import { Client, Sites, , , } from "@appwrite.io/console"; +import { Client, Sites, Framework, BuildRuntime, Adapter } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -9,15 +9,15 @@ const sites = new Sites(client); const result = await sites.create({ siteId: '<SITE_ID>', name: '<NAME>', - framework: .Analog, - buildRuntime: .Node145, + framework: Framework.Analog, + buildRuntime: BuildRuntime.Node145, enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: '<INSTALL_COMMAND>', // optional buildCommand: '<BUILD_COMMAND>', // optional outputDirectory: '<OUTPUT_DIRECTORY>', // optional - adapter: .Static, // optional + adapter: Adapter.Static, // optional installationId: '<INSTALLATION_ID>', // optional fallbackFile: '<FALLBACK_FILE>', // optional providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // optional diff --git a/docs/examples/1.8.x/console-web/examples/sites/update.md b/docs/examples/1.8.x/console-web/examples/sites/update.md index 68bd073c50..c68fe2924b 100644 --- a/docs/examples/1.8.x/console-web/examples/sites/update.md +++ b/docs/examples/1.8.x/console-web/examples/sites/update.md @@ -1,4 +1,4 @@ -import { Client, Sites, , , } from "@appwrite.io/console"; +import { Client, Sites, Framework, BuildRuntime, Adapter } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -9,15 +9,15 @@ const sites = new Sites(client); const result = await sites.update({ siteId: '<SITE_ID>', name: '<NAME>', - framework: .Analog, + framework: Framework.Analog, enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: '<INSTALL_COMMAND>', // optional buildCommand: '<BUILD_COMMAND>', // optional outputDirectory: '<OUTPUT_DIRECTORY>', // optional - buildRuntime: .Node145, // optional - adapter: .Static, // optional + buildRuntime: BuildRuntime.Node145, // optional + adapter: Adapter.Static, // optional fallbackFile: '<FALLBACK_FILE>', // optional installationId: '<INSTALLATION_ID>', // optional providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // optional diff --git a/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md b/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md index 343568a408..19ddf890a9 100644 --- a/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/console-web/examples/storage/create-bucket.md @@ -1,4 +1,4 @@ -import { Client, Storage, , Permission, Role } from "@appwrite.io/console"; +import { Client, Storage, Compression, Permission, Role } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -14,7 +14,7 @@ const result = await storage.createBucket({ enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: [], // optional - compression: .None, // optional + compression: Compression.None, // optional encryption: false, // optional antivirus: false // optional }); diff --git a/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md b/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md index b2c2eaa885..70ef0ef759 100644 --- a/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/console-web/examples/storage/update-bucket.md @@ -1,4 +1,4 @@ -import { Client, Storage, , Permission, Role } from "@appwrite.io/console"; +import { Client, Storage, Compression, Permission, Role } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint @@ -14,7 +14,7 @@ const result = await storage.updateBucket({ enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: [], // optional - compression: .None, // optional + compression: Compression.None, // optional encryption: false, // optional antivirus: false // optional }); diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md index 8d5287511d..1f326e8066 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-browser.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getBrowser( +Uint8List result = await avatars.getBrowser( code: Browser.avantBrowser, width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md index 88fe35ebd9..8232d7b2b9 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-credit-card.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getCreditCard( +Uint8List result = await avatars.getCreditCard( code: CreditCard.americanExpress, width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md index d4cd8eae83..e2df21f6fd 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-favicon.md @@ -7,6 +7,6 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getFavicon( +Uint8List result = await avatars.getFavicon( url: 'https://example.com', ); diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md index 56046681bc..0aea028e5b 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-flag.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getFlag( +Uint8List result = await avatars.getFlag( code: Flag.afghanistan, width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md index b6db1858c5..fc727f481e 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-image.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getImage( +Uint8List result = await avatars.getImage( url: 'https://example.com', width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md index 7dc0989b4d..be77c67147 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-initials.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getInitials( +Uint8List result = await avatars.getInitials( name: '<NAME>', // (optional) width: 0, // (optional) height: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md index f64fe8a4ff..f44ce59076 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-qr.md @@ -7,7 +7,7 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getQR( +Uint8List result = await avatars.getQR( text: '<TEXT>', size: 1, // (optional) margin: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md index 7630648f98..c787a82298 100644 --- a/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-dart/examples/avatars/get-screenshot.md @@ -7,17 +7,17 @@ Client client = Client() Avatars avatars = Avatars(client); -UInt8List result = await avatars.getScreenshot( +Uint8List result = await avatars.getScreenshot( url: 'https://example.com', headers: {}, // (optional) viewportWidth: 1, // (optional) viewportHeight: 1, // (optional) scale: 0.1, // (optional) - theme: .light, // (optional) + theme: Theme.light, // (optional) userAgent: '<USER_AGENT>', // (optional) fullpage: false, // (optional) locale: '<LOCALE>', // (optional) - timezone: .africaAbidjan, // (optional) + timezone: Timezone.africaAbidjan, // (optional) latitude: -90, // (optional) longitude: -180, // (optional) accuracy: 0, // (optional) @@ -27,5 +27,5 @@ UInt8List result = await avatars.getScreenshot( width: 0, // (optional) height: 0, // (optional) quality: -1, // (optional) - output: .jpg, // (optional) + output: Output.jpg, // (optional) ); diff --git a/docs/examples/1.8.x/server-dart/examples/functions/create.md b/docs/examples/1.8.x/server-dart/examples/functions/create.md index f3f2683000..2276872e91 100644 --- a/docs/examples/1.8.x/server-dart/examples/functions/create.md +++ b/docs/examples/1.8.x/server-dart/examples/functions/create.md @@ -10,7 +10,7 @@ Functions functions = Functions(client); Func result = await functions.create( functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: .node145, + runtime: Runtime.node145, execute: ["any"], // (optional) events: [], // (optional) schedule: '', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md b/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md index e7bbacf344..1b93e3bad9 100644 --- a/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-dart/examples/functions/get-deployment-download.md @@ -7,7 +7,7 @@ Client client = Client() Functions functions = Functions(client); -UInt8List result = await functions.getDeploymentDownload( +Uint8List result = await functions.getDeploymentDownload( functionId: '<FUNCTION_ID>', deploymentId: '<DEPLOYMENT_ID>', type: DeploymentDownloadType.source, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/functions/update.md b/docs/examples/1.8.x/server-dart/examples/functions/update.md index ebe3be8cc6..bf3e39cc56 100644 --- a/docs/examples/1.8.x/server-dart/examples/functions/update.md +++ b/docs/examples/1.8.x/server-dart/examples/functions/update.md @@ -10,7 +10,7 @@ Functions functions = Functions(client); Func result = await functions.update( functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: .node145, // (optional) + runtime: Runtime.node145, // (optional) execute: ["any"], // (optional) events: [], // (optional) schedule: '', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/server-dart/examples/health/get-failed-jobs.md index 6f80718f6b..b375c5793c 100644 --- a/docs/examples/1.8.x/server-dart/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-dart/examples/health/get-failed-jobs.md @@ -8,6 +8,6 @@ Client client = Client() Health health = Health(client); HealthQueue result = await health.getFailedJobs( - name: .v1Database, + name: Name.v1Database, threshold: 0, // (optional) ); diff --git a/docs/examples/1.8.x/server-dart/examples/sites/create.md b/docs/examples/1.8.x/server-dart/examples/sites/create.md index 448abab1df..e6ec4a6da8 100644 --- a/docs/examples/1.8.x/server-dart/examples/sites/create.md +++ b/docs/examples/1.8.x/server-dart/examples/sites/create.md @@ -10,15 +10,15 @@ Sites sites = Sites(client); Site result = await sites.create( siteId: '<SITE_ID>', name: '<NAME>', - framework: .analog, - buildRuntime: .node145, + framework: Framework.analog, + buildRuntime: BuildRuntime.node145, enabled: false, // (optional) logging: false, // (optional) timeout: 1, // (optional) installCommand: '<INSTALL_COMMAND>', // (optional) buildCommand: '<BUILD_COMMAND>', // (optional) outputDirectory: '<OUTPUT_DIRECTORY>', // (optional) - adapter: .static, // (optional) + adapter: Adapter.static, // (optional) installationId: '<INSTALLATION_ID>', // (optional) fallbackFile: '<FALLBACK_FILE>', // (optional) providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md b/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md index ad21070b8a..f6bbb3c35d 100644 --- a/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-dart/examples/sites/get-deployment-download.md @@ -7,7 +7,7 @@ Client client = Client() Sites sites = Sites(client); -UInt8List result = await sites.getDeploymentDownload( +Uint8List result = await sites.getDeploymentDownload( siteId: '<SITE_ID>', deploymentId: '<DEPLOYMENT_ID>', type: DeploymentDownloadType.source, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/sites/update.md b/docs/examples/1.8.x/server-dart/examples/sites/update.md index c13acfb25b..2cfd68633b 100644 --- a/docs/examples/1.8.x/server-dart/examples/sites/update.md +++ b/docs/examples/1.8.x/server-dart/examples/sites/update.md @@ -10,15 +10,15 @@ Sites sites = Sites(client); Site result = await sites.update( siteId: '<SITE_ID>', name: '<NAME>', - framework: .analog, + framework: Framework.analog, enabled: false, // (optional) logging: false, // (optional) timeout: 1, // (optional) installCommand: '<INSTALL_COMMAND>', // (optional) buildCommand: '<BUILD_COMMAND>', // (optional) outputDirectory: '<OUTPUT_DIRECTORY>', // (optional) - buildRuntime: .node145, // (optional) - adapter: .static, // (optional) + buildRuntime: BuildRuntime.node145, // (optional) + adapter: Adapter.static, // (optional) fallbackFile: '<FALLBACK_FILE>', // (optional) installationId: '<INSTALLATION_ID>', // (optional) providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md index 79357d0e4a..ad0ff92f66 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/create-bucket.md @@ -17,7 +17,7 @@ Bucket result = await storage.createBucket( enabled: false, // (optional) maximumFileSize: 1, // (optional) allowedFileExtensions: [], // (optional) - compression: .none, // (optional) + compression: Compression.none, // (optional) encryption: false, // (optional) antivirus: false, // (optional) ); diff --git a/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md b/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md index 8c119c386c..34f40685fe 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/get-file-download.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); -UInt8List result = await storage.getFileDownload( +Uint8List result = await storage.getFileDownload( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md b/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md index a1f3c09b33..a14e12c630 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/get-file-preview.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); -UInt8List result = await storage.getFilePreview( +Uint8List result = await storage.getFilePreview( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', width: 0, // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md b/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md index d48b51c19c..a1d9271f13 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/get-file-view.md @@ -7,7 +7,7 @@ Client client = Client() Storage storage = Storage(client); -UInt8List result = await storage.getFileView( +Uint8List result = await storage.getFileView( bucketId: '<BUCKET_ID>', fileId: '<FILE_ID>', token: '<TOKEN>', // (optional) diff --git a/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md index f3eea941a3..4a51d03596 100644 --- a/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-dart/examples/storage/update-bucket.md @@ -17,7 +17,7 @@ Bucket result = await storage.updateBucket( enabled: false, // (optional) maximumFileSize: 1, // (optional) allowedFileExtensions: [], // (optional) - compression: .none, // (optional) + compression: Compression.none, // (optional) encryption: false, // (optional) antivirus: false, // (optional) ); diff --git a/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md index f5c3542a97..e2e5462484 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-dotnet/examples/avatars/get-screenshot.md @@ -16,11 +16,11 @@ byte[] result = await avatars.GetScreenshot( viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: .Light, // optional + theme: Theme.Light, // optional userAgent: "<USER_AGENT>", // optional fullpage: false, // optional locale: "<LOCALE>", // optional - timezone: .AfricaAbidjan, // optional + timezone: Timezone.AfricaAbidjan, // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -30,5 +30,5 @@ byte[] result = await avatars.GetScreenshot( width: 0, // optional height: 0, // optional quality: -1, // optional - output: .Jpg // optional + output: Output.Jpg // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-dotnet/examples/functions/create.md b/docs/examples/1.8.x/server-dotnet/examples/functions/create.md index 6e705228f1..7d26480d68 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/functions/create.md +++ b/docs/examples/1.8.x/server-dotnet/examples/functions/create.md @@ -13,7 +13,7 @@ Functions functions = new Functions(client); Function result = await functions.Create( functionId: "<FUNCTION_ID>", name: "<NAME>", - runtime: .Node145, + runtime: Runtime.Node145, execute: ["any"], // optional events: new List<string>(), // optional schedule: "", // optional diff --git a/docs/examples/1.8.x/server-dotnet/examples/functions/update.md b/docs/examples/1.8.x/server-dotnet/examples/functions/update.md index 7160795f77..a41a0fd331 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/functions/update.md +++ b/docs/examples/1.8.x/server-dotnet/examples/functions/update.md @@ -13,7 +13,7 @@ Functions functions = new Functions(client); Function result = await functions.Update( functionId: "<FUNCTION_ID>", name: "<NAME>", - runtime: .Node145, // optional + runtime: Runtime.Node145, // optional execute: ["any"], // optional events: new List<string>(), // optional schedule: "", // optional diff --git a/docs/examples/1.8.x/server-dotnet/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/server-dotnet/examples/health/get-failed-jobs.md index 4d43479831..ee0aceaace 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-dotnet/examples/health/get-failed-jobs.md @@ -11,6 +11,6 @@ Client client = new Client() Health health = new Health(client); HealthQueue result = await health.GetFailedJobs( - name: .V1Database, + name: Name.V1Database, threshold: 0 // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-dotnet/examples/sites/create.md b/docs/examples/1.8.x/server-dotnet/examples/sites/create.md index 025adca41d..ed7360d5f2 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/sites/create.md +++ b/docs/examples/1.8.x/server-dotnet/examples/sites/create.md @@ -13,15 +13,15 @@ Sites sites = new Sites(client); Site result = await sites.Create( siteId: "<SITE_ID>", name: "<NAME>", - framework: .Analog, - buildRuntime: .Node145, + framework: Framework.Analog, + buildRuntime: BuildRuntime.Node145, enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: "<INSTALL_COMMAND>", // optional buildCommand: "<BUILD_COMMAND>", // optional outputDirectory: "<OUTPUT_DIRECTORY>", // optional - adapter: .Static, // optional + adapter: Adapter.Static, // optional installationId: "<INSTALLATION_ID>", // optional fallbackFile: "<FALLBACK_FILE>", // optional providerRepositoryId: "<PROVIDER_REPOSITORY_ID>", // optional diff --git a/docs/examples/1.8.x/server-dotnet/examples/sites/update.md b/docs/examples/1.8.x/server-dotnet/examples/sites/update.md index c25e3f6df9..32da483318 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/sites/update.md +++ b/docs/examples/1.8.x/server-dotnet/examples/sites/update.md @@ -13,15 +13,15 @@ Sites sites = new Sites(client); Site result = await sites.Update( siteId: "<SITE_ID>", name: "<NAME>", - framework: .Analog, + framework: Framework.Analog, enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: "<INSTALL_COMMAND>", // optional buildCommand: "<BUILD_COMMAND>", // optional outputDirectory: "<OUTPUT_DIRECTORY>", // optional - buildRuntime: .Node145, // optional - adapter: .Static, // optional + buildRuntime: BuildRuntime.Node145, // optional + adapter: Adapter.Static, // optional fallbackFile: "<FALLBACK_FILE>", // optional installationId: "<INSTALLATION_ID>", // optional providerRepositoryId: "<PROVIDER_REPOSITORY_ID>", // optional diff --git a/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md index f009f694ad..e76358f551 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-dotnet/examples/storage/create-bucket.md @@ -18,7 +18,7 @@ Bucket result = await storage.CreateBucket( enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: new List<string>(), // optional - compression: .None, // optional + compression: Compression.None, // optional encryption: false, // optional antivirus: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md index d41a45961c..3cfdfcc482 100644 --- a/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-dotnet/examples/storage/update-bucket.md @@ -18,7 +18,7 @@ Bucket result = await storage.UpdateBucket( enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: new List<string>(), // optional - compression: .None, // optional + compression: Compression.None, // optional encryption: false, // optional antivirus: false // optional ); \ No newline at end of file diff --git a/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md b/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md index cf734af3b2..0f1cb9c2f0 100644 --- a/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-kotlin/java/avatars/get-screenshot.md @@ -1,6 +1,9 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Avatars; +import io.appwrite.enums.Theme; +import io.appwrite.enums.Timezone; +import io.appwrite.enums.Output; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -15,11 +18,11 @@ avatars.getScreenshot( 1, // viewportWidth (optional) 1, // viewportHeight (optional) 0.1, // scale (optional) - .LIGHT, // theme (optional) + Theme.LIGHT, // theme (optional) "<USER_AGENT>", // userAgent (optional) false, // fullpage (optional) "<LOCALE>", // locale (optional) - .AFRICA_ABIDJAN, // timezone (optional) + Timezone.AFRICA_ABIDJAN, // timezone (optional) -90, // latitude (optional) -180, // longitude (optional) 0, // accuracy (optional) @@ -29,7 +32,7 @@ avatars.getScreenshot( 0, // width (optional) 0, // height (optional) -1, // quality (optional) - .JPG, // output (optional) + Output.JPG, // output (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/1.8.x/server-kotlin/java/databases/create-relationship-attribute.md b/docs/examples/1.8.x/server-kotlin/java/databases/create-relationship-attribute.md index a67f452647..580be890ba 100644 --- a/docs/examples/1.8.x/server-kotlin/java/databases/create-relationship-attribute.md +++ b/docs/examples/1.8.x/server-kotlin/java/databases/create-relationship-attribute.md @@ -2,6 +2,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Databases; import io.appwrite.enums.RelationshipType; +import io.appwrite.enums.RelationMutate; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/databases/update-relationship-attribute.md b/docs/examples/1.8.x/server-kotlin/java/databases/update-relationship-attribute.md index 8af20e91a9..998f0beb16 100644 --- a/docs/examples/1.8.x/server-kotlin/java/databases/update-relationship-attribute.md +++ b/docs/examples/1.8.x/server-kotlin/java/databases/update-relationship-attribute.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Databases; +import io.appwrite.enums.RelationMutate; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/functions/create-execution.md b/docs/examples/1.8.x/server-kotlin/java/functions/create-execution.md index 93efa0adf8..4abfe236b3 100644 --- a/docs/examples/1.8.x/server-kotlin/java/functions/create-execution.md +++ b/docs/examples/1.8.x/server-kotlin/java/functions/create-execution.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Functions; +import io.appwrite.enums.ExecutionMethod; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/functions/create.md b/docs/examples/1.8.x/server-kotlin/java/functions/create.md index 71871287bb..587fd54b9b 100644 --- a/docs/examples/1.8.x/server-kotlin/java/functions/create.md +++ b/docs/examples/1.8.x/server-kotlin/java/functions/create.md @@ -13,7 +13,7 @@ Functions functions = new Functions(client); functions.create( "<FUNCTION_ID>", // functionId "<NAME>", // name - .NODE_14_5, // runtime + Runtime.NODE_14_5, // runtime listOf("any"), // execute (optional) listOf(), // events (optional) "", // schedule (optional) diff --git a/docs/examples/1.8.x/server-kotlin/java/functions/get-deployment-download.md b/docs/examples/1.8.x/server-kotlin/java/functions/get-deployment-download.md index d522b12caf..2b6d38a787 100644 --- a/docs/examples/1.8.x/server-kotlin/java/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-kotlin/java/functions/get-deployment-download.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Functions; +import io.appwrite.enums.DeploymentDownloadType; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/functions/update.md b/docs/examples/1.8.x/server-kotlin/java/functions/update.md index 5956c57b73..5cb560e200 100644 --- a/docs/examples/1.8.x/server-kotlin/java/functions/update.md +++ b/docs/examples/1.8.x/server-kotlin/java/functions/update.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Functions; +import io.appwrite.enums.Runtime; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -12,7 +13,7 @@ Functions functions = new Functions(client); functions.update( "<FUNCTION_ID>", // functionId "<NAME>", // name - .NODE_14_5, // runtime (optional) + Runtime.NODE_14_5, // runtime (optional) listOf("any"), // execute (optional) listOf(), // events (optional) "", // schedule (optional) diff --git a/docs/examples/1.8.x/server-kotlin/java/health/get-failed-jobs.md b/docs/examples/1.8.x/server-kotlin/java/health/get-failed-jobs.md index d2b81bd0bf..0495e265e6 100644 --- a/docs/examples/1.8.x/server-kotlin/java/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-kotlin/java/health/get-failed-jobs.md @@ -11,7 +11,7 @@ Client client = new Client() Health health = new Health(client); health.getFailedJobs( - .V1_DATABASE, // name + Name.V1_DATABASE, // name 0, // threshold (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { diff --git a/docs/examples/1.8.x/server-kotlin/java/messaging/create-push.md b/docs/examples/1.8.x/server-kotlin/java/messaging/create-push.md index 14e8ca2679..94119e6a93 100644 --- a/docs/examples/1.8.x/server-kotlin/java/messaging/create-push.md +++ b/docs/examples/1.8.x/server-kotlin/java/messaging/create-push.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Messaging; +import io.appwrite.enums.MessagePriority; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/messaging/create-smtp-provider.md b/docs/examples/1.8.x/server-kotlin/java/messaging/create-smtp-provider.md index 1f1a0f998f..966436e3c1 100644 --- a/docs/examples/1.8.x/server-kotlin/java/messaging/create-smtp-provider.md +++ b/docs/examples/1.8.x/server-kotlin/java/messaging/create-smtp-provider.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Messaging; +import io.appwrite.enums.SmtpEncryption; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/messaging/update-push.md b/docs/examples/1.8.x/server-kotlin/java/messaging/update-push.md index ce56683674..80ad6fcd30 100644 --- a/docs/examples/1.8.x/server-kotlin/java/messaging/update-push.md +++ b/docs/examples/1.8.x/server-kotlin/java/messaging/update-push.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Messaging; +import io.appwrite.enums.MessagePriority; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/messaging/update-smtp-provider.md b/docs/examples/1.8.x/server-kotlin/java/messaging/update-smtp-provider.md index 36f120033a..c8ab7571ce 100644 --- a/docs/examples/1.8.x/server-kotlin/java/messaging/update-smtp-provider.md +++ b/docs/examples/1.8.x/server-kotlin/java/messaging/update-smtp-provider.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Messaging; +import io.appwrite.enums.SmtpEncryption; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/sites/create.md b/docs/examples/1.8.x/server-kotlin/java/sites/create.md index 19664ec57b..11e0dbba6f 100644 --- a/docs/examples/1.8.x/server-kotlin/java/sites/create.md +++ b/docs/examples/1.8.x/server-kotlin/java/sites/create.md @@ -3,6 +3,7 @@ import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Sites; import io.appwrite.enums.Framework; import io.appwrite.enums.BuildRuntime; +import io.appwrite.enums.Adapter; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,15 +15,15 @@ Sites sites = new Sites(client); sites.create( "<SITE_ID>", // siteId "<NAME>", // name - .ANALOG, // framework - .NODE_14_5, // buildRuntime + Framework.ANALOG, // framework + BuildRuntime.NODE_14_5, // buildRuntime false, // enabled (optional) false, // logging (optional) 1, // timeout (optional) "<INSTALL_COMMAND>", // installCommand (optional) "<BUILD_COMMAND>", // buildCommand (optional) "<OUTPUT_DIRECTORY>", // outputDirectory (optional) - .STATIC, // adapter (optional) + Adapter.STATIC, // adapter (optional) "<INSTALLATION_ID>", // installationId (optional) "<FALLBACK_FILE>", // fallbackFile (optional) "<PROVIDER_REPOSITORY_ID>", // providerRepositoryId (optional) diff --git a/docs/examples/1.8.x/server-kotlin/java/sites/get-deployment-download.md b/docs/examples/1.8.x/server-kotlin/java/sites/get-deployment-download.md index 5875c7262f..ce26ba8cca 100644 --- a/docs/examples/1.8.x/server-kotlin/java/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-kotlin/java/sites/get-deployment-download.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Sites; +import io.appwrite.enums.DeploymentDownloadType; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/sites/update.md b/docs/examples/1.8.x/server-kotlin/java/sites/update.md index 9a8b577ce0..0c4024b841 100644 --- a/docs/examples/1.8.x/server-kotlin/java/sites/update.md +++ b/docs/examples/1.8.x/server-kotlin/java/sites/update.md @@ -2,6 +2,8 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Sites; import io.appwrite.enums.Framework; +import io.appwrite.enums.BuildRuntime; +import io.appwrite.enums.Adapter; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -13,15 +15,15 @@ Sites sites = new Sites(client); sites.update( "<SITE_ID>", // siteId "<NAME>", // name - .ANALOG, // framework + Framework.ANALOG, // framework false, // enabled (optional) false, // logging (optional) 1, // timeout (optional) "<INSTALL_COMMAND>", // installCommand (optional) "<BUILD_COMMAND>", // buildCommand (optional) "<OUTPUT_DIRECTORY>", // outputDirectory (optional) - .NODE_14_5, // buildRuntime (optional) - .STATIC, // adapter (optional) + BuildRuntime.NODE_14_5, // buildRuntime (optional) + Adapter.STATIC, // adapter (optional) "<FALLBACK_FILE>", // fallbackFile (optional) "<INSTALLATION_ID>", // installationId (optional) "<PROVIDER_REPOSITORY_ID>", // providerRepositoryId (optional) diff --git a/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md b/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md index d48db24094..dca688ed7d 100644 --- a/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/java/storage/create-bucket.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Storage; +import io.appwrite.enums.Compression; import io.appwrite.Permission; import io.appwrite.Role; @@ -19,7 +20,7 @@ storage.createBucket( false, // enabled (optional) 1, // maximumFileSize (optional) listOf(), // allowedFileExtensions (optional) - .NONE, // compression (optional) + Compression.NONE, // compression (optional) false, // encryption (optional) false, // antivirus (optional) new CoroutineCallback<>((result, error) -> { diff --git a/docs/examples/1.8.x/server-kotlin/java/storage/get-file-preview.md b/docs/examples/1.8.x/server-kotlin/java/storage/get-file-preview.md index 1a0ab596bc..61f7637256 100644 --- a/docs/examples/1.8.x/server-kotlin/java/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-kotlin/java/storage/get-file-preview.md @@ -1,6 +1,8 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Storage; +import io.appwrite.enums.ImageGravity; +import io.appwrite.enums.ImageFormat; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md b/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md index 586b113578..61c7e9e256 100644 --- a/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/java/storage/update-bucket.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Storage; +import io.appwrite.enums.Compression; import io.appwrite.Permission; import io.appwrite.Role; @@ -19,7 +20,7 @@ storage.updateBucket( false, // enabled (optional) 1, // maximumFileSize (optional) listOf(), // allowedFileExtensions (optional) - .NONE, // compression (optional) + Compression.NONE, // compression (optional) false, // encryption (optional) false, // antivirus (optional) new CoroutineCallback<>((result, error) -> { diff --git a/docs/examples/1.8.x/server-kotlin/java/tablesdb/create-relationship-column.md b/docs/examples/1.8.x/server-kotlin/java/tablesdb/create-relationship-column.md index 956c1fa516..c7a3a5f288 100644 --- a/docs/examples/1.8.x/server-kotlin/java/tablesdb/create-relationship-column.md +++ b/docs/examples/1.8.x/server-kotlin/java/tablesdb/create-relationship-column.md @@ -2,6 +2,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.TablesDB; import io.appwrite.enums.RelationshipType; +import io.appwrite.enums.RelationMutate; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/tablesdb/update-relationship-column.md b/docs/examples/1.8.x/server-kotlin/java/tablesdb/update-relationship-column.md index 45aea8ae41..eaf6b1ba52 100644 --- a/docs/examples/1.8.x/server-kotlin/java/tablesdb/update-relationship-column.md +++ b/docs/examples/1.8.x/server-kotlin/java/tablesdb/update-relationship-column.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.TablesDB; +import io.appwrite.enums.RelationMutate; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/java/users/create-sha-user.md b/docs/examples/1.8.x/server-kotlin/java/users/create-sha-user.md index ad729071c2..3a37ddce95 100644 --- a/docs/examples/1.8.x/server-kotlin/java/users/create-sha-user.md +++ b/docs/examples/1.8.x/server-kotlin/java/users/create-sha-user.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Users; +import io.appwrite.enums.PasswordHash; Client client = new Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md b/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md index 96032bb8a4..eca5493c57 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/avatars/get-screenshot.md @@ -1,6 +1,9 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Avatars +import io.appwrite.enums.Theme +import io.appwrite.enums.Timezone +import io.appwrite.enums.Output val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/databases/create-relationship-attribute.md b/docs/examples/1.8.x/server-kotlin/kotlin/databases/create-relationship-attribute.md index 1bf610321a..48389f529d 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/databases/create-relationship-attribute.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/databases/create-relationship-attribute.md @@ -2,6 +2,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Databases import io.appwrite.enums.RelationshipType +import io.appwrite.enums.RelationMutate val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/databases/update-relationship-attribute.md b/docs/examples/1.8.x/server-kotlin/kotlin/databases/update-relationship-attribute.md index 001dd1a391..baf69e3602 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/databases/update-relationship-attribute.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/databases/update-relationship-attribute.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Databases +import io.appwrite.enums.RelationMutate val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-execution.md b/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-execution.md index 2734412232..9458be08e0 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-execution.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/functions/create-execution.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Functions +import io.appwrite.enums.ExecutionMethod val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/functions/create.md b/docs/examples/1.8.x/server-kotlin/kotlin/functions/create.md index c0ea4de201..de5b191b3f 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/functions/create.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/functions/create.md @@ -13,7 +13,7 @@ val functions = Functions(client) val response = functions.create( functionId = "<FUNCTION_ID>", name = "<NAME>", - runtime = .NODE_14_5, + runtime = Runtime.NODE_14_5, execute = listOf("any"), // optional events = listOf(), // optional schedule = "", // optional diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/functions/get-deployment-download.md b/docs/examples/1.8.x/server-kotlin/kotlin/functions/get-deployment-download.md index 634cfae3b4..8a16397dc9 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/functions/get-deployment-download.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Functions +import io.appwrite.enums.DeploymentDownloadType val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/functions/update.md b/docs/examples/1.8.x/server-kotlin/kotlin/functions/update.md index 7f0b33ebd7..1b7db783c1 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/functions/update.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/functions/update.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Functions +import io.appwrite.enums.Runtime val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/health/get-failed-jobs.md b/docs/examples/1.8.x/server-kotlin/kotlin/health/get-failed-jobs.md index 027df127cc..646d9b368d 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/health/get-failed-jobs.md @@ -11,6 +11,6 @@ val client = Client() val health = Health(client) val response = health.getFailedJobs( - name = .V1_DATABASE, + name = Name.V1_DATABASE, threshold = 0 // optional ) diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-push.md b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-push.md index d0d765a32a..e17406915c 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-push.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-push.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Messaging +import io.appwrite.enums.MessagePriority val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-smtp-provider.md b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-smtp-provider.md index ce50130e80..c7dca02027 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-smtp-provider.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/create-smtp-provider.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Messaging +import io.appwrite.enums.SmtpEncryption val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-push.md b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-push.md index 0b9c4c6535..5e2c77d569 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-push.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-push.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Messaging +import io.appwrite.enums.MessagePriority val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-smtp-provider.md b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-smtp-provider.md index 7652e53166..66900e747d 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-smtp-provider.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/messaging/update-smtp-provider.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Messaging +import io.appwrite.enums.SmtpEncryption val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/sites/create.md b/docs/examples/1.8.x/server-kotlin/kotlin/sites/create.md index a5e9719faf..8df2d0709f 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/sites/create.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/sites/create.md @@ -3,6 +3,7 @@ import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Sites import io.appwrite.enums.Framework import io.appwrite.enums.BuildRuntime +import io.appwrite.enums.Adapter val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -14,8 +15,8 @@ val sites = Sites(client) val response = sites.create( siteId = "<SITE_ID>", name = "<NAME>", - framework = .ANALOG, - buildRuntime = .NODE_14_5, + framework = Framework.ANALOG, + buildRuntime = BuildRuntime.NODE_14_5, enabled = false, // optional logging = false, // optional timeout = 1, // optional diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/sites/get-deployment-download.md b/docs/examples/1.8.x/server-kotlin/kotlin/sites/get-deployment-download.md index 84324762cc..a313a5de7e 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/sites/get-deployment-download.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Sites +import io.appwrite.enums.DeploymentDownloadType val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/sites/update.md b/docs/examples/1.8.x/server-kotlin/kotlin/sites/update.md index 4b4a938d95..ee6f7db73f 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/sites/update.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/sites/update.md @@ -2,6 +2,8 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Sites import io.appwrite.enums.Framework +import io.appwrite.enums.BuildRuntime +import io.appwrite.enums.Adapter val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint @@ -13,7 +15,7 @@ val sites = Sites(client) val response = sites.update( siteId = "<SITE_ID>", name = "<NAME>", - framework = .ANALOG, + framework = Framework.ANALOG, enabled = false, // optional logging = false, // optional timeout = 1, // optional diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md b/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md index 872932eeff..006466ec3e 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/storage/create-bucket.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Storage +import io.appwrite.enums.Compression import io.appwrite.Permission import io.appwrite.Role diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/storage/get-file-preview.md b/docs/examples/1.8.x/server-kotlin/kotlin/storage/get-file-preview.md index 45122de2f8..7b39d85cfa 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/storage/get-file-preview.md @@ -1,6 +1,8 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Storage +import io.appwrite.enums.ImageGravity +import io.appwrite.enums.ImageFormat val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md b/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md index cb8187343e..38f34ed046 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/storage/update-bucket.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Storage +import io.appwrite.enums.Compression import io.appwrite.Permission import io.appwrite.Role diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/create-relationship-column.md b/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/create-relationship-column.md index fbdf36532f..3ece593a96 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/create-relationship-column.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/create-relationship-column.md @@ -2,6 +2,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.TablesDB import io.appwrite.enums.RelationshipType +import io.appwrite.enums.RelationMutate val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/update-relationship-column.md b/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/update-relationship-column.md index f69defd8ec..357a57cd11 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/update-relationship-column.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/tablesdb/update-relationship-column.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.TablesDB +import io.appwrite.enums.RelationMutate val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-kotlin/kotlin/users/create-sha-user.md b/docs/examples/1.8.x/server-kotlin/kotlin/users/create-sha-user.md index 17a157b2cd..b286f8a554 100644 --- a/docs/examples/1.8.x/server-kotlin/kotlin/users/create-sha-user.md +++ b/docs/examples/1.8.x/server-kotlin/kotlin/users/create-sha-user.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Users +import io.appwrite.enums.PasswordHash val client = Client() .setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint diff --git a/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md index 5f7b40cece..60a38988cb 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-nodejs/examples/avatars/get-screenshot.md @@ -13,11 +13,11 @@ const result = await avatars.getScreenshot({ viewportWidth: 1, // optional viewportHeight: 1, // optional scale: 0.1, // optional - theme: sdk..Light, // optional + theme: sdk.Theme.Light, // optional userAgent: '<USER_AGENT>', // optional fullpage: false, // optional locale: '<LOCALE>', // optional - timezone: sdk..AfricaAbidjan, // optional + timezone: sdk.Timezone.AfricaAbidjan, // optional latitude: -90, // optional longitude: -180, // optional accuracy: 0, // optional @@ -27,5 +27,5 @@ const result = await avatars.getScreenshot({ width: 0, // optional height: 0, // optional quality: -1, // optional - output: sdk..Jpg // optional + output: sdk.Output.Jpg // optional }); diff --git a/docs/examples/1.8.x/server-nodejs/examples/functions/create.md b/docs/examples/1.8.x/server-nodejs/examples/functions/create.md index d9f21ff796..37ac89dc5a 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/functions/create.md +++ b/docs/examples/1.8.x/server-nodejs/examples/functions/create.md @@ -10,7 +10,7 @@ const functions = new sdk.Functions(client); const result = await functions.create({ functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: sdk..Node145, + runtime: sdk.Runtime.Node145, execute: ["any"], // optional events: [], // optional schedule: '', // optional diff --git a/docs/examples/1.8.x/server-nodejs/examples/functions/update.md b/docs/examples/1.8.x/server-nodejs/examples/functions/update.md index 8ed2828f56..60653b5b77 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/functions/update.md +++ b/docs/examples/1.8.x/server-nodejs/examples/functions/update.md @@ -10,7 +10,7 @@ const functions = new sdk.Functions(client); const result = await functions.update({ functionId: '<FUNCTION_ID>', name: '<NAME>', - runtime: sdk..Node145, // optional + runtime: sdk.Runtime.Node145, // optional execute: ["any"], // optional events: [], // optional schedule: '', // optional diff --git a/docs/examples/1.8.x/server-nodejs/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/server-nodejs/examples/health/get-failed-jobs.md index bf77aa26d8..32c03426b8 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-nodejs/examples/health/get-failed-jobs.md @@ -8,6 +8,6 @@ const client = new sdk.Client() const health = new sdk.Health(client); const result = await health.getFailedJobs({ - name: sdk..V1Database, + name: sdk.Name.V1Database, threshold: null // optional }); diff --git a/docs/examples/1.8.x/server-nodejs/examples/sites/create.md b/docs/examples/1.8.x/server-nodejs/examples/sites/create.md index 25c6715748..397d2d3934 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/sites/create.md +++ b/docs/examples/1.8.x/server-nodejs/examples/sites/create.md @@ -10,15 +10,15 @@ const sites = new sdk.Sites(client); const result = await sites.create({ siteId: '<SITE_ID>', name: '<NAME>', - framework: sdk..Analog, - buildRuntime: sdk..Node145, + framework: sdk.Framework.Analog, + buildRuntime: sdk.BuildRuntime.Node145, enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: '<INSTALL_COMMAND>', // optional buildCommand: '<BUILD_COMMAND>', // optional outputDirectory: '<OUTPUT_DIRECTORY>', // optional - adapter: sdk..Static, // optional + adapter: sdk.Adapter.Static, // optional installationId: '<INSTALLATION_ID>', // optional fallbackFile: '<FALLBACK_FILE>', // optional providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // optional diff --git a/docs/examples/1.8.x/server-nodejs/examples/sites/update.md b/docs/examples/1.8.x/server-nodejs/examples/sites/update.md index 5cb52f7a3c..1a919f5d38 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/sites/update.md +++ b/docs/examples/1.8.x/server-nodejs/examples/sites/update.md @@ -10,15 +10,15 @@ const sites = new sdk.Sites(client); const result = await sites.update({ siteId: '<SITE_ID>', name: '<NAME>', - framework: sdk..Analog, + framework: sdk.Framework.Analog, enabled: false, // optional logging: false, // optional timeout: 1, // optional installCommand: '<INSTALL_COMMAND>', // optional buildCommand: '<BUILD_COMMAND>', // optional outputDirectory: '<OUTPUT_DIRECTORY>', // optional - buildRuntime: sdk..Node145, // optional - adapter: sdk..Static, // optional + buildRuntime: sdk.BuildRuntime.Node145, // optional + adapter: sdk.Adapter.Static, // optional fallbackFile: '<FALLBACK_FILE>', // optional installationId: '<INSTALLATION_ID>', // optional providerRepositoryId: '<PROVIDER_REPOSITORY_ID>', // optional diff --git a/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md index b47d2c8353..b3557130e3 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-nodejs/examples/storage/create-bucket.md @@ -15,7 +15,7 @@ const result = await storage.createBucket({ enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: [], // optional - compression: sdk..None, // optional + compression: sdk.Compression.None, // optional encryption: false, // optional antivirus: false // optional }); diff --git a/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md index 9535914eeb..988b71ee45 100644 --- a/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-nodejs/examples/storage/update-bucket.md @@ -15,7 +15,7 @@ const result = await storage.updateBucket({ enabled: false, // optional maximumFileSize: 1, // optional allowedFileExtensions: [], // optional - compression: sdk..None, // optional + compression: sdk.Compression.None, // optional encryption: false, // optional antivirus: false // optional }); diff --git a/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md index 34bdf8ac7a..fe7073eceb 100644 --- a/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-python/examples/avatars/get-screenshot.md @@ -1,5 +1,8 @@ from appwrite.client import Client from appwrite.services.avatars import Avatars +from appwrite.enums import Theme +from appwrite.enums import Timezone +from appwrite.enums import Output client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -14,11 +17,11 @@ result = avatars.get_screenshot( viewport_width = 1, # optional viewport_height = 1, # optional scale = 0.1, # optional - theme = .LIGHT, # optional + theme = Theme.LIGHT, # optional user_agent = '<USER_AGENT>', # optional fullpage = False, # optional locale = '<LOCALE>', # optional - timezone = .AFRICA_ABIDJAN, # optional + timezone = Timezone.AFRICA_ABIDJAN, # optional latitude = -90, # optional longitude = -180, # optional accuracy = 0, # optional @@ -28,5 +31,5 @@ result = avatars.get_screenshot( width = 0, # optional height = 0, # optional quality = -1, # optional - output = .JPG # optional + output = Output.JPG # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/databases/create-relationship-attribute.md b/docs/examples/1.8.x/server-python/examples/databases/create-relationship-attribute.md index 6c8f4dc5bb..ea859fcc33 100644 --- a/docs/examples/1.8.x/server-python/examples/databases/create-relationship-attribute.md +++ b/docs/examples/1.8.x/server-python/examples/databases/create-relationship-attribute.md @@ -1,6 +1,7 @@ from appwrite.client import Client from appwrite.services.databases import Databases from appwrite.enums import RelationshipType +from appwrite.enums import RelationMutate client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/databases/update-relationship-attribute.md b/docs/examples/1.8.x/server-python/examples/databases/update-relationship-attribute.md index 3b6c8e93e9..8f5b0d8e69 100644 --- a/docs/examples/1.8.x/server-python/examples/databases/update-relationship-attribute.md +++ b/docs/examples/1.8.x/server-python/examples/databases/update-relationship-attribute.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.databases import Databases +from appwrite.enums import RelationMutate client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/functions/create-execution.md b/docs/examples/1.8.x/server-python/examples/functions/create-execution.md index f80b8646c2..8361351b35 100644 --- a/docs/examples/1.8.x/server-python/examples/functions/create-execution.md +++ b/docs/examples/1.8.x/server-python/examples/functions/create-execution.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.functions import Functions +from appwrite.enums import ExecutionMethod client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/functions/create.md b/docs/examples/1.8.x/server-python/examples/functions/create.md index 8758e27e50..98e16ebebe 100644 --- a/docs/examples/1.8.x/server-python/examples/functions/create.md +++ b/docs/examples/1.8.x/server-python/examples/functions/create.md @@ -1,6 +1,6 @@ from appwrite.client import Client from appwrite.services.functions import Functions -from appwrite.enums import +from appwrite.enums import Runtime client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -12,7 +12,7 @@ functions = Functions(client) result = functions.create( function_id = '<FUNCTION_ID>', name = '<NAME>', - runtime = .NODE_14_5, + runtime = Runtime.NODE_14_5, execute = ["any"], # optional events = [], # optional schedule = '', # optional diff --git a/docs/examples/1.8.x/server-python/examples/functions/get-deployment-download.md b/docs/examples/1.8.x/server-python/examples/functions/get-deployment-download.md index 1b0673c468..c633a893c6 100644 --- a/docs/examples/1.8.x/server-python/examples/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-python/examples/functions/get-deployment-download.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.functions import Functions +from appwrite.enums import DeploymentDownloadType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/functions/update.md b/docs/examples/1.8.x/server-python/examples/functions/update.md index 64ee39b29d..841c1eb839 100644 --- a/docs/examples/1.8.x/server-python/examples/functions/update.md +++ b/docs/examples/1.8.x/server-python/examples/functions/update.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.functions import Functions +from appwrite.enums import Runtime client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -11,7 +12,7 @@ functions = Functions(client) result = functions.update( function_id = '<FUNCTION_ID>', name = '<NAME>', - runtime = .NODE_14_5, # optional + runtime = Runtime.NODE_14_5, # optional execute = ["any"], # optional events = [], # optional schedule = '', # optional diff --git a/docs/examples/1.8.x/server-python/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/server-python/examples/health/get-failed-jobs.md index 5362a2d02a..6db282447e 100644 --- a/docs/examples/1.8.x/server-python/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-python/examples/health/get-failed-jobs.md @@ -1,6 +1,6 @@ from appwrite.client import Client from appwrite.services.health import Health -from appwrite.enums import +from appwrite.enums import Name client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -10,6 +10,6 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key health = Health(client) result = health.get_failed_jobs( - name = .V1_DATABASE, + name = Name.V1_DATABASE, threshold = None # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/messaging/create-push.md b/docs/examples/1.8.x/server-python/examples/messaging/create-push.md index b706234227..817c157ee7 100644 --- a/docs/examples/1.8.x/server-python/examples/messaging/create-push.md +++ b/docs/examples/1.8.x/server-python/examples/messaging/create-push.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging +from appwrite.enums import MessagePriority client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/messaging/create-smtp-provider.md b/docs/examples/1.8.x/server-python/examples/messaging/create-smtp-provider.md index 99914f0779..6b9c345e6c 100644 --- a/docs/examples/1.8.x/server-python/examples/messaging/create-smtp-provider.md +++ b/docs/examples/1.8.x/server-python/examples/messaging/create-smtp-provider.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging +from appwrite.enums import SmtpEncryption client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/messaging/update-push.md b/docs/examples/1.8.x/server-python/examples/messaging/update-push.md index ce5d39466f..f9901329bb 100644 --- a/docs/examples/1.8.x/server-python/examples/messaging/update-push.md +++ b/docs/examples/1.8.x/server-python/examples/messaging/update-push.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging +from appwrite.enums import MessagePriority client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/messaging/update-smtp-provider.md b/docs/examples/1.8.x/server-python/examples/messaging/update-smtp-provider.md index 80019aad40..51f54a3df8 100644 --- a/docs/examples/1.8.x/server-python/examples/messaging/update-smtp-provider.md +++ b/docs/examples/1.8.x/server-python/examples/messaging/update-smtp-provider.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging +from appwrite.enums import SmtpEncryption client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/sites/create.md b/docs/examples/1.8.x/server-python/examples/sites/create.md index 4950cd2116..436e56ab86 100644 --- a/docs/examples/1.8.x/server-python/examples/sites/create.md +++ b/docs/examples/1.8.x/server-python/examples/sites/create.md @@ -1,7 +1,8 @@ from appwrite.client import Client from appwrite.services.sites import Sites -from appwrite.enums import -from appwrite.enums import +from appwrite.enums import Framework +from appwrite.enums import BuildRuntime +from appwrite.enums import Adapter client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,15 +14,15 @@ sites = Sites(client) result = sites.create( site_id = '<SITE_ID>', name = '<NAME>', - framework = .ANALOG, - build_runtime = .NODE_14_5, + framework = Framework.ANALOG, + build_runtime = BuildRuntime.NODE_14_5, enabled = False, # optional logging = False, # optional timeout = 1, # optional install_command = '<INSTALL_COMMAND>', # optional build_command = '<BUILD_COMMAND>', # optional output_directory = '<OUTPUT_DIRECTORY>', # optional - adapter = .STATIC, # optional + adapter = Adapter.STATIC, # optional installation_id = '<INSTALLATION_ID>', # optional fallback_file = '<FALLBACK_FILE>', # optional provider_repository_id = '<PROVIDER_REPOSITORY_ID>', # optional diff --git a/docs/examples/1.8.x/server-python/examples/sites/get-deployment-download.md b/docs/examples/1.8.x/server-python/examples/sites/get-deployment-download.md index d6af564217..7eaa105ad3 100644 --- a/docs/examples/1.8.x/server-python/examples/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-python/examples/sites/get-deployment-download.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.sites import Sites +from appwrite.enums import DeploymentDownloadType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/sites/update.md b/docs/examples/1.8.x/server-python/examples/sites/update.md index 7d2d2865a4..56b796c276 100644 --- a/docs/examples/1.8.x/server-python/examples/sites/update.md +++ b/docs/examples/1.8.x/server-python/examples/sites/update.md @@ -1,6 +1,8 @@ from appwrite.client import Client from appwrite.services.sites import Sites -from appwrite.enums import +from appwrite.enums import Framework +from appwrite.enums import BuildRuntime +from appwrite.enums import Adapter client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -12,15 +14,15 @@ sites = Sites(client) result = sites.update( site_id = '<SITE_ID>', name = '<NAME>', - framework = .ANALOG, + framework = Framework.ANALOG, enabled = False, # optional logging = False, # optional timeout = 1, # optional install_command = '<INSTALL_COMMAND>', # optional build_command = '<BUILD_COMMAND>', # optional output_directory = '<OUTPUT_DIRECTORY>', # optional - build_runtime = .NODE_14_5, # optional - adapter = .STATIC, # optional + build_runtime = BuildRuntime.NODE_14_5, # optional + adapter = Adapter.STATIC, # optional fallback_file = '<FALLBACK_FILE>', # optional installation_id = '<INSTALLATION_ID>', # optional provider_repository_id = '<PROVIDER_REPOSITORY_ID>', # optional diff --git a/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md index e08b2d0d6b..a2a3f9280c 100644 --- a/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-python/examples/storage/create-bucket.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.storage import Storage +from appwrite.enums import Compression from appwrite.permission import Permission from appwrite.role import Role @@ -18,7 +19,7 @@ result = storage.create_bucket( enabled = False, # optional maximum_file_size = 1, # optional allowed_file_extensions = [], # optional - compression = .NONE, # optional + compression = Compression.NONE, # optional encryption = False, # optional antivirus = False # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/storage/get-file-preview.md b/docs/examples/1.8.x/server-python/examples/storage/get-file-preview.md index 47e3f23b55..f962edc0b6 100644 --- a/docs/examples/1.8.x/server-python/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-python/examples/storage/get-file-preview.md @@ -1,5 +1,7 @@ from appwrite.client import Client from appwrite.services.storage import Storage +from appwrite.enums import ImageGravity +from appwrite.enums import ImageFormat client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md index bfa7cc3fdb..b095d314ac 100644 --- a/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-python/examples/storage/update-bucket.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.storage import Storage +from appwrite.enums import Compression from appwrite.permission import Permission from appwrite.role import Role @@ -18,7 +19,7 @@ result = storage.update_bucket( enabled = False, # optional maximum_file_size = 1, # optional allowed_file_extensions = [], # optional - compression = .NONE, # optional + compression = Compression.NONE, # optional encryption = False, # optional antivirus = False # optional ) diff --git a/docs/examples/1.8.x/server-python/examples/tablesdb/create-relationship-column.md b/docs/examples/1.8.x/server-python/examples/tablesdb/create-relationship-column.md index 16acbf8fb8..d72fbfda11 100644 --- a/docs/examples/1.8.x/server-python/examples/tablesdb/create-relationship-column.md +++ b/docs/examples/1.8.x/server-python/examples/tablesdb/create-relationship-column.md @@ -1,6 +1,7 @@ from appwrite.client import Client from appwrite.services.tables_db import TablesDB from appwrite.enums import RelationshipType +from appwrite.enums import RelationMutate client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/tablesdb/update-relationship-column.md b/docs/examples/1.8.x/server-python/examples/tablesdb/update-relationship-column.md index 1cb93dbdf2..560590ec8c 100644 --- a/docs/examples/1.8.x/server-python/examples/tablesdb/update-relationship-column.md +++ b/docs/examples/1.8.x/server-python/examples/tablesdb/update-relationship-column.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.tables_db import TablesDB +from appwrite.enums import RelationMutate client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-python/examples/users/create-sha-user.md b/docs/examples/1.8.x/server-python/examples/users/create-sha-user.md index 5b4c8f831a..7722c62f0c 100644 --- a/docs/examples/1.8.x/server-python/examples/users/create-sha-user.md +++ b/docs/examples/1.8.x/server-python/examples/users/create-sha-user.md @@ -1,5 +1,6 @@ from appwrite.client import Client from appwrite.services.users import Users +from appwrite.enums import PasswordHash client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md b/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md index f2af537fe8..f66fae3e02 100644 --- a/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md +++ b/docs/examples/1.8.x/server-ruby/examples/avatars/get-screenshot.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -15,11 +16,11 @@ result = avatars.get_screenshot( viewport_width: 1, # optional viewport_height: 1, # optional scale: 0.1, # optional - theme: ::LIGHT, # optional + theme: Theme::LIGHT, # optional user_agent: '<USER_AGENT>', # optional fullpage: false, # optional locale: '<LOCALE>', # optional - timezone: ::AFRICA_ABIDJAN, # optional + timezone: Timezone::AFRICA_ABIDJAN, # optional latitude: -90, # optional longitude: -180, # optional accuracy: 0, # optional @@ -29,5 +30,5 @@ result = avatars.get_screenshot( width: 0, # optional height: 0, # optional quality: -1, # optional - output: ::JPG # optional + output: Output::JPG # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/databases/update-relationship-attribute.md b/docs/examples/1.8.x/server-ruby/examples/databases/update-relationship-attribute.md index 679edb823e..6fddac2d58 100644 --- a/docs/examples/1.8.x/server-ruby/examples/databases/update-relationship-attribute.md +++ b/docs/examples/1.8.x/server-ruby/examples/databases/update-relationship-attribute.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/functions/create-execution.md b/docs/examples/1.8.x/server-ruby/examples/functions/create-execution.md index 666b995d77..521ee7cde0 100644 --- a/docs/examples/1.8.x/server-ruby/examples/functions/create-execution.md +++ b/docs/examples/1.8.x/server-ruby/examples/functions/create-execution.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/functions/create.md b/docs/examples/1.8.x/server-ruby/examples/functions/create.md index cad021b5f8..ce16a2b998 100644 --- a/docs/examples/1.8.x/server-ruby/examples/functions/create.md +++ b/docs/examples/1.8.x/server-ruby/examples/functions/create.md @@ -13,7 +13,7 @@ functions = Functions.new(client) result = functions.create( function_id: '<FUNCTION_ID>', name: '<NAME>', - runtime: ::NODE_14_5, + runtime: Runtime::NODE_14_5, execute: ["any"], # optional events: [], # optional schedule: '', # optional diff --git a/docs/examples/1.8.x/server-ruby/examples/functions/get-deployment-download.md b/docs/examples/1.8.x/server-ruby/examples/functions/get-deployment-download.md index a1a50a5f94..06faa7e03c 100644 --- a/docs/examples/1.8.x/server-ruby/examples/functions/get-deployment-download.md +++ b/docs/examples/1.8.x/server-ruby/examples/functions/get-deployment-download.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/functions/update.md b/docs/examples/1.8.x/server-ruby/examples/functions/update.md index 45b6e32ab3..91d8436463 100644 --- a/docs/examples/1.8.x/server-ruby/examples/functions/update.md +++ b/docs/examples/1.8.x/server-ruby/examples/functions/update.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -12,7 +13,7 @@ functions = Functions.new(client) result = functions.update( function_id: '<FUNCTION_ID>', name: '<NAME>', - runtime: ::NODE_14_5, # optional + runtime: Runtime::NODE_14_5, # optional execute: ["any"], # optional events: [], # optional schedule: '', # optional diff --git a/docs/examples/1.8.x/server-ruby/examples/health/get-failed-jobs.md b/docs/examples/1.8.x/server-ruby/examples/health/get-failed-jobs.md index 73e1983e3a..b15f6cc41e 100644 --- a/docs/examples/1.8.x/server-ruby/examples/health/get-failed-jobs.md +++ b/docs/examples/1.8.x/server-ruby/examples/health/get-failed-jobs.md @@ -11,6 +11,6 @@ client = Client.new health = Health.new(client) result = health.get_failed_jobs( - name: ::V1_DATABASE, + name: Name::V1_DATABASE, threshold: null # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/messaging/create-push.md b/docs/examples/1.8.x/server-ruby/examples/messaging/create-push.md index f4555aa967..547c179d68 100644 --- a/docs/examples/1.8.x/server-ruby/examples/messaging/create-push.md +++ b/docs/examples/1.8.x/server-ruby/examples/messaging/create-push.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/messaging/create-smtp-provider.md b/docs/examples/1.8.x/server-ruby/examples/messaging/create-smtp-provider.md index b062e574b4..c33f772a7d 100644 --- a/docs/examples/1.8.x/server-ruby/examples/messaging/create-smtp-provider.md +++ b/docs/examples/1.8.x/server-ruby/examples/messaging/create-smtp-provider.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/messaging/update-push.md b/docs/examples/1.8.x/server-ruby/examples/messaging/update-push.md index 19b273bb24..b365069ad0 100644 --- a/docs/examples/1.8.x/server-ruby/examples/messaging/update-push.md +++ b/docs/examples/1.8.x/server-ruby/examples/messaging/update-push.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/messaging/update-smtp-provider.md b/docs/examples/1.8.x/server-ruby/examples/messaging/update-smtp-provider.md index bbaebf3c32..ab0e1b45cf 100644 --- a/docs/examples/1.8.x/server-ruby/examples/messaging/update-smtp-provider.md +++ b/docs/examples/1.8.x/server-ruby/examples/messaging/update-smtp-provider.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/sites/create.md b/docs/examples/1.8.x/server-ruby/examples/sites/create.md index 2243185485..7dc004cd71 100644 --- a/docs/examples/1.8.x/server-ruby/examples/sites/create.md +++ b/docs/examples/1.8.x/server-ruby/examples/sites/create.md @@ -13,15 +13,15 @@ sites = Sites.new(client) result = sites.create( site_id: '<SITE_ID>', name: '<NAME>', - framework: ::ANALOG, - build_runtime: ::NODE_14_5, + framework: Framework::ANALOG, + build_runtime: BuildRuntime::NODE_14_5, enabled: false, # optional logging: false, # optional timeout: 1, # optional install_command: '<INSTALL_COMMAND>', # optional build_command: '<BUILD_COMMAND>', # optional output_directory: '<OUTPUT_DIRECTORY>', # optional - adapter: ::STATIC, # optional + adapter: Adapter::STATIC, # optional installation_id: '<INSTALLATION_ID>', # optional fallback_file: '<FALLBACK_FILE>', # optional provider_repository_id: '<PROVIDER_REPOSITORY_ID>', # optional diff --git a/docs/examples/1.8.x/server-ruby/examples/sites/get-deployment-download.md b/docs/examples/1.8.x/server-ruby/examples/sites/get-deployment-download.md index 85162626ba..c82ab98879 100644 --- a/docs/examples/1.8.x/server-ruby/examples/sites/get-deployment-download.md +++ b/docs/examples/1.8.x/server-ruby/examples/sites/get-deployment-download.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/sites/update.md b/docs/examples/1.8.x/server-ruby/examples/sites/update.md index 922255ab65..0d73293124 100644 --- a/docs/examples/1.8.x/server-ruby/examples/sites/update.md +++ b/docs/examples/1.8.x/server-ruby/examples/sites/update.md @@ -13,15 +13,15 @@ sites = Sites.new(client) result = sites.update( site_id: '<SITE_ID>', name: '<NAME>', - framework: ::ANALOG, + framework: Framework::ANALOG, enabled: false, # optional logging: false, # optional timeout: 1, # optional install_command: '<INSTALL_COMMAND>', # optional build_command: '<BUILD_COMMAND>', # optional output_directory: '<OUTPUT_DIRECTORY>', # optional - build_runtime: ::NODE_14_5, # optional - adapter: ::STATIC, # optional + build_runtime: BuildRuntime::NODE_14_5, # optional + adapter: Adapter::STATIC, # optional fallback_file: '<FALLBACK_FILE>', # optional installation_id: '<INSTALLATION_ID>', # optional provider_repository_id: '<PROVIDER_REPOSITORY_ID>', # optional diff --git a/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md b/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md index 4a12518fb7..3db21e2a35 100644 --- a/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md +++ b/docs/examples/1.8.x/server-ruby/examples/storage/create-bucket.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums include Appwrite::Permission include Appwrite::Role @@ -19,7 +20,7 @@ result = storage.create_bucket( enabled: false, # optional maximum_file_size: 1, # optional allowed_file_extensions: [], # optional - compression: ::NONE, # optional + compression: Compression::NONE, # optional encryption: false, # optional antivirus: false # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/storage/get-file-preview.md b/docs/examples/1.8.x/server-ruby/examples/storage/get-file-preview.md index 23254615d3..4b154c772d 100644 --- a/docs/examples/1.8.x/server-ruby/examples/storage/get-file-preview.md +++ b/docs/examples/1.8.x/server-ruby/examples/storage/get-file-preview.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md b/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md index 2e44aad536..0eaecbe0d7 100644 --- a/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md +++ b/docs/examples/1.8.x/server-ruby/examples/storage/update-bucket.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums include Appwrite::Permission include Appwrite::Role @@ -19,7 +20,7 @@ result = storage.update_bucket( enabled: false, # optional maximum_file_size: 1, # optional allowed_file_extensions: [], # optional - compression: ::NONE, # optional + compression: Compression::NONE, # optional encryption: false, # optional antivirus: false # optional ) diff --git a/docs/examples/1.8.x/server-ruby/examples/tablesdb/update-relationship-column.md b/docs/examples/1.8.x/server-ruby/examples/tablesdb/update-relationship-column.md index 3951cbc047..81de2d7897 100644 --- a/docs/examples/1.8.x/server-ruby/examples/tablesdb/update-relationship-column.md +++ b/docs/examples/1.8.x/server-ruby/examples/tablesdb/update-relationship-column.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/1.8.x/server-ruby/examples/users/create-sha-user.md b/docs/examples/1.8.x/server-ruby/examples/users/create-sha-user.md index f3951d9c80..d19db05324 100644 --- a/docs/examples/1.8.x/server-ruby/examples/users/create-sha-user.md +++ b/docs/examples/1.8.x/server-ruby/examples/users/create-sha-user.md @@ -1,6 +1,7 @@ require 'appwrite' include Appwrite +include Appwrite::Enums client = Client.new .set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint From 20221cd6b6ed44d8ee2e873e3a9749c796ce82b6 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 11:43:27 +0530 Subject: [PATCH 152/167] sync composer --- composer.json | 2 +- composer.lock | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 0a4e347d7f..1cff497d08 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,7 @@ }, "require-dev": { "ext-fileinfo": "*", - "appwrite/sdk-generator": "dev-fix-enum-rendering", + "appwrite/sdk-generator": "*", "phpunit/phpunit": "9.*", "swoole/ide-helper": "5.1.2", "phpstan/phpstan": "1.8.*", diff --git a/composer.lock b/composer.lock index f173903669..163bdb5bd9 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": "bc877cc8bf639e146710e0d7656adbec", + "content-hash": "3b502f78f5e31f2ea7b4c69e3301283a", "packages": [ { "name": "adhocore/jwt", @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "dev-fix-enum-rendering", + "version": "1.5.7", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "3f39061b0db19057219bab6352afa2201306eedf" + "reference": "dc6720ba92ed98e2c62b2a319d4371f167ccc808" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/3f39061b0db19057219bab6352afa2201306eedf", - "reference": "3f39061b0db19057219bab6352afa2201306eedf", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/dc6720ba92ed98e2c62b2a319d4371f167ccc808", + "reference": "dc6720ba92ed98e2c62b2a319d4371f167ccc808", "shasum": "" }, "require": { @@ -5428,9 +5428,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/fix-enum-rendering" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.7" }, - "time": "2025-11-18T05:35:14+00:00" + "time": "2025-11-18T05:57:01+00:00" }, { "name": "doctrine/annotations", @@ -8897,9 +8897,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "appwrite/sdk-generator": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { From c2645be4e1159e733a18ef2dfe54e802b79dcda4 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 12:47:39 +0530 Subject: [PATCH 153/167] chore: custom format instance in specs --- src/Appwrite/Platform/Tasks/Specs.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index 53cbced174..c69558d096 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -43,6 +43,15 @@ class Specs extends Action return new AppwriteResponse(new SwooleResponse()); } + protected function getFormatInstance(string $format, array $arguments) + { + return match ($format) { + 'swagger2' => new Swagger2(...$arguments), + 'open-api3' => new OpenAPI3(...$arguments), + default => throw new Exception('Format not found: ' . $format) + }; + } + public function __construct() { $this @@ -288,12 +297,7 @@ class Specs extends Action ]; foreach (['swagger2', 'open-api3'] as $format) { - $formatInstance = match ($format) { - 'swagger2' => new Swagger2(...$arguments), - 'open-api3' => new OpenAPI3(...$arguments), - default => throw new Exception('Format not found: ' . $format) - }; - + $formatInstance = $this->getFormatInstance($format, $arguments); $specs = new Specification($formatInstance); $endpoint = System::getEnv('_APP_HOME', '[HOSTNAME]'); $email = System::getEnv('_APP_SYSTEM_TEAM_EMAIL', APP_EMAIL_TEAM); From 5a8a900b1881f9e898750afd36d6aa77b1c53821 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Tue, 18 Nov 2025 12:50:22 +0530 Subject: [PATCH 154/167] format --- src/Appwrite/Platform/Tasks/Specs.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index c69558d096..edb1fc56ed 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -44,13 +44,13 @@ class Specs extends Action } protected function getFormatInstance(string $format, array $arguments) - { - return match ($format) { - 'swagger2' => new Swagger2(...$arguments), - 'open-api3' => new OpenAPI3(...$arguments), - default => throw new Exception('Format not found: ' . $format) - }; - } + { + return match ($format) { + 'swagger2' => new Swagger2(...$arguments), + 'open-api3' => new OpenAPI3(...$arguments), + default => throw new Exception('Format not found: ' . $format) + }; + } public function __construct() { From ce2f2d0ebcdc2439c87ff00b5a394a0b82f8fc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Tue, 18 Nov 2025 16:35:02 +0100 Subject: [PATCH 155/167] Use config library for dotenv adapter --- app/controllers/api/vcs.php | 26 +++++++------ app/init/configs.php | 75 +++++++++++++++++++------------------ composer.json | 2 +- composer.lock | 55 ++++++++++++++------------- 4 files changed, 84 insertions(+), 74 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 4703e3a296..82f23cf6b5 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -17,7 +17,9 @@ use Appwrite\Vcs\Comment; use Swoole\Coroutine\WaitGroup; use Utopia\App; use Utopia\CLI\Console; +use Utopia\Config\Adapters\PHP as ConfigPHP; use Utopia\Config\Config; +use Utopia\Config\Exceptions\Parse; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; @@ -978,14 +980,14 @@ App::post('/v1/vcs/github/installations/:installationId/detections') $contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/' . $file); $envFile = $contentResponse['content'] ?? ''; - $envLines = \explode("\n", $envFile); - foreach ($envLines as $line) { - $parts = \explode('=', $line, 2); - $envName = \trim($parts[0] ?? ''); - $envValue = \trim($parts[1] ?? ''); - if (!empty($envName)) { + $configAdapter = new ConfigPHP(); + try { + $envObject = $configAdapter->parse($envFile); + foreach ($envObject as $envName => $envValue) { $envs[$envName] = $envValue; } + } catch (Parse $err) { + // Silence error, so rest of endpoint can return } } finally { $wg->done(); @@ -1192,14 +1194,14 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') $contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], $file); $envFile = $contentResponse['content'] ?? ''; - $envLines = \explode("\n", $envFile); - foreach ($envLines as $line) { - $parts = \explode('=', $line, 2); - $envName = \trim($parts[0] ?? ''); - $envValue = \trim($parts[1] ?? ''); - if (!empty($envName)) { + $configAdapter = new ConfigPHP(); + try { + $envObject = $configAdapter->parse($envFile); + foreach ($envObject as $envName => $envValue) { $envs[$envName] = $envValue; } + } catch (Parse) { + // Silence error, so rest of endpoint can return } } finally { $wg->done(); diff --git a/app/init/configs.php b/app/init/configs.php index 7572302919..9519c757b3 100644 --- a/app/init/configs.php +++ b/app/init/configs.php @@ -1,42 +1,45 @@ <?php +use Utopia\Config\Adapters\PHP; use Utopia\Config\Config; require_once __DIR__ . '/../config/storage/resource_limits.php'; -Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php'); -Config::load('events', __DIR__ . '/../config/events.php'); -Config::load('auth', __DIR__ . '/../config/auth.php'); -Config::load('apis', __DIR__ . '/../config/apis.php'); // List of APIs -Config::load('errors', __DIR__ . '/../config/errors.php'); -Config::load('oAuthProviders', __DIR__ . '/../config/oAuthProviders.php'); -Config::load('platforms', __DIR__ . '/../config/platforms.php'); -Config::load('console', __DIR__ . '/../config/console.php'); -Config::load('collections', __DIR__ . '/../config/collections.php'); -Config::load('frameworks', __DIR__ . '/../config/frameworks.php'); -Config::load('runtimes', __DIR__ . '/../config/runtimes.php'); -Config::load('runtimes-v2', __DIR__ . '/../config/runtimes-v2.php'); -Config::load('usage', __DIR__ . '/../config/usage.php'); -Config::load('roles', __DIR__ . '/../config/roles.php'); // User roles and scopes -Config::load('scopes', __DIR__ . '/../config/scopes.php'); // User roles and scopes -Config::load('services', __DIR__ . '/../config/services.php'); // List of services -Config::load('variables', __DIR__ . '/../config/variables.php'); // List of env variables -Config::load('regions', __DIR__ . '/../config/regions.php'); // List of available regions -Config::load('avatar-browsers', __DIR__ . '/../config/avatars/browsers.php'); -Config::load('avatar-credit-cards', __DIR__ . '/../config/avatars/credit-cards.php'); -Config::load('avatar-flags', __DIR__ . '/../config/avatars/flags.php'); -Config::load('locale-codes', __DIR__ . '/../config/locale/codes.php'); -Config::load('locale-currencies', __DIR__ . '/../config/locale/currencies.php'); -Config::load('locale-eu', __DIR__ . '/../config/locale/eu.php'); -Config::load('locale-languages', __DIR__ . '/../config/locale/languages.php'); -Config::load('locale-phones', __DIR__ . '/../config/locale/phones.php'); -Config::load('locale-countries', __DIR__ . '/../config/locale/countries.php'); -Config::load('locale-continents', __DIR__ . '/../config/locale/continents.php'); -Config::load('locale-templates', __DIR__ . '/../config/locale/templates.php'); -Config::load('storage-logos', __DIR__ . '/../config/storage/logos.php'); -Config::load('storage-mimes', __DIR__ . '/../config/storage/mimes.php'); -Config::load('storage-inputs', __DIR__ . '/../config/storage/inputs.php'); -Config::load('storage-outputs', __DIR__ . '/../config/storage/outputs.php'); -Config::load('specifications', __DIR__ . '/../config/specifications.php'); -Config::load('templates-function', __DIR__ . '/../config/templates/function.php'); -Config::load('templates-site', __DIR__ . '/../config/templates/site.php'); +$configAdapter = new PHP(); + +Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php', new PHP()); +Config::load('events', __DIR__ . '/../config/events.php', new PHP()); +Config::load('auth', __DIR__ . '/../config/auth.php', new PHP()); +Config::load('apis', __DIR__ . '/../config/apis.php', new PHP()); // List of APIs +Config::load('errors', __DIR__ . '/../config/errors.php', new PHP()); +Config::load('oAuthProviders', __DIR__ . '/../config/oAuthProviders.php', new PHP()); +Config::load('platforms', __DIR__ . '/../config/platforms.php', new PHP()); +Config::load('console', __DIR__ . '/../config/console.php', new PHP()); +Config::load('collections', __DIR__ . '/../config/collections.php', new PHP()); +Config::load('frameworks', __DIR__ . '/../config/frameworks.php', new PHP()); +Config::load('runtimes', __DIR__ . '/../config/runtimes.php', new PHP()); +Config::load('runtimes-v2', __DIR__ . '/../config/runtimes-v2.php', new PHP()); +Config::load('usage', __DIR__ . '/../config/usage.php', new PHP()); +Config::load('roles', __DIR__ . '/../config/roles.php', new PHP()); // User roles and scopes +Config::load('scopes', __DIR__ . '/../config/scopes.php', new PHP()); // User roles and scopes +Config::load('services', __DIR__ . '/../config/services.php', new PHP()); // List of services +Config::load('variables', __DIR__ . '/../config/variables.php', new PHP()); // List of env variables +Config::load('regions', __DIR__ . '/../config/regions.php', new PHP()); // List of available regions +Config::load('avatar-browsers', __DIR__ . '/../config/avatars/browsers.php', new PHP()); +Config::load('avatar-credit-cards', __DIR__ . '/../config/avatars/credit-cards.php', new PHP()); +Config::load('avatar-flags', __DIR__ . '/../config/avatars/flags.php', new PHP()); +Config::load('locale-codes', __DIR__ . '/../config/locale/codes.php', new PHP()); +Config::load('locale-currencies', __DIR__ . '/../config/locale/currencies.php', new PHP()); +Config::load('locale-eu', __DIR__ . '/../config/locale/eu.php', new PHP()); +Config::load('locale-languages', __DIR__ . '/../config/locale/languages.php', new PHP()); +Config::load('locale-phones', __DIR__ . '/../config/locale/phones.php', new PHP()); +Config::load('locale-countries', __DIR__ . '/../config/locale/countries.php', new PHP()); +Config::load('locale-continents', __DIR__ . '/../config/locale/continents.php', new PHP()); +Config::load('locale-templates', __DIR__ . '/../config/locale/templates.php', new PHP()); +Config::load('storage-logos', __DIR__ . '/../config/storage/logos.php', new PHP()); +Config::load('storage-mimes', __DIR__ . '/../config/storage/mimes.php', new PHP()); +Config::load('storage-inputs', __DIR__ . '/../config/storage/inputs.php', new PHP()); +Config::load('storage-outputs', __DIR__ . '/../config/storage/outputs.php', new PHP()); +Config::load('specifications', __DIR__ . '/../config/specifications.php', new PHP()); +Config::load('templates-function', __DIR__ . '/../config/templates/function.php', new PHP()); +Config::load('templates-site', __DIR__ . '/../config/templates/site.php', new PHP()); diff --git a/composer.json b/composer.json index 1cff497d08..eec3e3e876 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "utopia-php/audit": "1.*", "utopia-php/cache": "0.13.*", "utopia-php/cli": "0.15.*", - "utopia-php/config": "0.2.*", + "utopia-php/config": "dev-feat-config-adapters as 1.0.0", "utopia-php/database": "4.*", "utopia-php/detector": "0.2.*", "utopia-php/domains": "0.9.*", diff --git a/composer.lock b/composer.lock index 163bdb5bd9..5856a5f2eb 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": "3b502f78f5e31f2ea7b4c69e3301283a", + "content-hash": "1042498bc589543427184b001fef3a1e", "packages": [ { "name": "adhocore/jwt", @@ -3745,24 +3745,26 @@ }, { "name": "utopia-php/config", - "version": "0.2.2", + "version": "dev-feat-config-adapters", "source": { "type": "git", "url": "https://github.com/utopia-php/config.git", - "reference": "a3d7bc0312d7150d5e04b1362dc34b2b136908cc" + "reference": "02232da489a94576be0d8fb63c326003ccb6e337" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/config/zipball/a3d7bc0312d7150d5e04b1362dc34b2b136908cc", - "reference": "a3d7bc0312d7150d5e04b1362dc34b2b136908cc", + "url": "https://api.github.com/repos/utopia-php/config/zipball/02232da489a94576be0d8fb63c326003ccb6e337", + "reference": "02232da489a94576be0d8fb63c326003ccb6e337", "shasum": "" }, "require": { - "php": ">=7.3" + "ext-yaml": "*", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "vimeo/psalm": "4.0.1" + "laravel/pint": "1.2.*", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^9.3" }, "type": "library", "autoload": { @@ -3774,12 +3776,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - } - ], "description": "A simple Config library to managing application config variables", "keywords": [ "config", @@ -3790,9 +3786,9 @@ ], "support": { "issues": "https://github.com/utopia-php/config/issues", - "source": "https://github.com/utopia-php/config/tree/0.2.2" + "source": "https://github.com/utopia-php/config/tree/feat-config-adapters" }, - "time": "2020-10-24T09:49:09+00:00" + "time": "2025-11-18T14:59:26+00:00" }, { "name": "utopia-php/console", @@ -4212,16 +4208,16 @@ }, { "name": "utopia-php/framework", - "version": "0.33.29", + "version": "0.33.30", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "6e63939fdb33b847f92839499cd6e8df626c278d" + "reference": "07cf699a7c47bd1a03b4da1812f1719a66b3c924" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/6e63939fdb33b847f92839499cd6e8df626c278d", - "reference": "6e63939fdb33b847f92839499cd6e8df626c278d", + "url": "https://api.github.com/repos/utopia-php/http/zipball/07cf699a7c47bd1a03b4da1812f1719a66b3c924", + "reference": "07cf699a7c47bd1a03b4da1812f1719a66b3c924", "shasum": "" }, "require": { @@ -4253,9 +4249,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/0.33.29" + "source": "https://github.com/utopia-php/http/tree/0.33.30" }, - "time": "2025-11-14T06:33:29+00:00" + "time": "2025-11-18T12:18:00+00:00" }, { "name": "utopia-php/image", @@ -8895,9 +8891,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/config", + "version": "dev-feat-config-adapters", + "alias": "1.0.0", + "alias_normalized": "1.0.0.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/config": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8921,5 +8926,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } From e3ee7241782f688e992640c5f59e5c99bb2531f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Tue, 18 Nov 2025 16:42:57 +0100 Subject: [PATCH 156/167] Fix during QA --- app/controllers/api/vcs.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 82f23cf6b5..05bd2f83e5 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -17,7 +17,7 @@ use Appwrite\Vcs\Comment; use Swoole\Coroutine\WaitGroup; use Utopia\App; use Utopia\CLI\Console; -use Utopia\Config\Adapters\PHP as ConfigPHP; +use Utopia\Config\Adapters\Dotenv as ConfigDotenv; use Utopia\Config\Config; use Utopia\Config\Exceptions\Parse; use Utopia\Database\Database; @@ -980,7 +980,7 @@ App::post('/v1/vcs/github/installations/:installationId/detections') $contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/' . $file); $envFile = $contentResponse['content'] ?? ''; - $configAdapter = new ConfigPHP(); + $configAdapter = new ConfigDotenv(); try { $envObject = $configAdapter->parse($envFile); foreach ($envObject as $envName => $envValue) { @@ -1194,7 +1194,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') $contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], $file); $envFile = $contentResponse['content'] ?? ''; - $configAdapter = new ConfigPHP(); + $configAdapter = new ConfigDotenv(); try { $envObject = $configAdapter->parse($envFile); foreach ($envObject as $envName => $envValue) { From 8765d5650a7ca2babc6a5e920f7498175ed953a3 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Wed, 19 Nov 2025 16:21:06 +1300 Subject: [PATCH 157/167] Revert "Merge pull request #10682 from appwrite/refactor-auth-single-instance" This reverts commit 919b01a1b164c12438e313a848a5c47aad4fe347, reversing changes made to deb503935244006b0f16da65d4d6fd6f09c92d7d. --- app/cli.php | 28 +-- app/config/storage/resource_limits.php | 4 +- app/controllers/api/account.php | 139 +++++------- app/controllers/api/avatars.php | 29 ++- app/controllers/api/graphql.php | 5 +- app/controllers/api/messaging.php | 65 +++--- app/controllers/api/migrations.php | 34 +-- app/controllers/api/project.php | 9 +- app/controllers/api/storage.php | 202 +++++++++--------- app/controllers/api/teams.php | 138 ++++++------ app/controllers/api/users.php | 6 +- app/controllers/api/vcs.php | 60 +++--- app/controllers/general.php | 62 +++--- app/controllers/shared/api.php | 53 +++-- app/controllers/shared/api/auth.php | 7 +- app/http.php | 28 +-- app/init/database/filters.php | 15 +- app/init/resources.php | 96 ++++----- app/realtime.php | 23 +- app/worker.php | 49 ++--- composer.json | 2 +- composer.lock | 42 ++-- src/Appwrite/Auth/Auth.php | 4 +- src/Appwrite/Databases/TransactionState.php | 10 +- src/Appwrite/Migration/Migration.php | 6 +- .../Platform/Modules/Compute/Base.php | 8 +- .../Modules/Console/Http/Resources/Get.php | 6 +- .../Collections/Attributes/Action.php | 10 +- .../Collections/Attributes/Boolean/Create.php | 6 +- .../Collections/Attributes/Boolean/Update.php | 5 +- .../Attributes/Datetime/Create.php | 7 +- .../Attributes/Datetime/Update.php | 5 +- .../Collections/Attributes/Delete.php | 5 +- .../Collections/Attributes/Email/Create.php | 7 +- .../Collections/Attributes/Email/Update.php | 5 +- .../Collections/Attributes/Enum/Create.php | 7 +- .../Collections/Attributes/Enum/Update.php | 5 +- .../Collections/Attributes/Float/Create.php | 6 +- .../Collections/Attributes/Float/Update.php | 5 +- .../Databases/Collections/Attributes/Get.php | 5 +- .../Collections/Attributes/IP/Create.php | 7 +- .../Collections/Attributes/IP/Update.php | 5 +- .../Collections/Attributes/Integer/Create.php | 6 +- .../Collections/Attributes/Integer/Update.php | 5 +- .../Collections/Attributes/Line/Create.php | 6 +- .../Collections/Attributes/Line/Update.php | 5 +- .../Collections/Attributes/Point/Create.php | 6 +- .../Collections/Attributes/Point/Update.php | 5 +- .../Collections/Attributes/Polygon/Create.php | 6 +- .../Collections/Attributes/Polygon/Update.php | 5 +- .../Attributes/Relationship/Create.php | 7 +- .../Attributes/Relationship/Update.php | 6 +- .../Collections/Attributes/String/Create.php | 8 +- .../Collections/Attributes/String/Update.php | 6 +- .../Collections/Attributes/URL/Create.php | 7 +- .../Collections/Attributes/URL/Update.php | 6 +- .../Collections/Attributes/XList.php | 5 +- .../Http/Databases/Collections/Create.php | 5 +- .../Http/Databases/Collections/Delete.php | 5 +- .../Collections/Documents/Action.php | 7 +- .../Documents/Attribute/Decrement.php | 13 +- .../Documents/Attribute/Increment.php | 13 +- .../Collections/Documents/Create.php | 43 ++-- .../Collections/Documents/Delete.php | 17 +- .../Databases/Collections/Documents/Get.php | 12 +- .../Collections/Documents/Logs/XList.php | 5 +- .../Collections/Documents/Update.php | 26 ++- .../Collections/Documents/Upsert.php | 26 ++- .../Databases/Collections/Documents/XList.php | 16 +- .../Http/Databases/Collections/Get.php | 5 +- .../Databases/Collections/Indexes/Create.php | 5 +- .../Databases/Collections/Indexes/Delete.php | 5 +- .../Databases/Collections/Indexes/Get.php | 5 +- .../Databases/Collections/Indexes/XList.php | 7 +- .../Http/Databases/Collections/Logs/XList.php | 39 ++-- .../Http/Databases/Collections/Update.php | 5 +- .../Http/Databases/Collections/Usage/Get.php | 5 +- .../Http/Databases/Collections/XList.php | 5 +- .../Http/Databases/Transactions/Create.php | 5 +- .../Transactions/Operations/Create.php | 34 ++- .../Http/Databases/Transactions/Update.php | 37 ++-- .../Databases/Http/Databases/Usage/Get.php | 5 +- .../Databases/Http/Databases/Usage/XList.php | 5 +- .../Tables/Columns/Boolean/Create.php | 1 - .../Tables/Columns/Boolean/Update.php | 1 - .../Tables/Columns/Datetime/Create.php | 1 - .../Tables/Columns/Datetime/Update.php | 1 - .../Http/TablesDB/Tables/Columns/Delete.php | 1 - .../TablesDB/Tables/Columns/Email/Create.php | 1 - .../TablesDB/Tables/Columns/Email/Update.php | 1 - .../TablesDB/Tables/Columns/Enum/Create.php | 1 - .../TablesDB/Tables/Columns/Enum/Update.php | 1 - .../TablesDB/Tables/Columns/Float/Create.php | 1 - .../TablesDB/Tables/Columns/Float/Update.php | 1 - .../Http/TablesDB/Tables/Columns/Get.php | 1 - .../TablesDB/Tables/Columns/IP/Create.php | 1 - .../TablesDB/Tables/Columns/IP/Update.php | 1 - .../Tables/Columns/Integer/Create.php | 1 - .../Tables/Columns/Integer/Update.php | 1 - .../TablesDB/Tables/Columns/Line/Create.php | 1 - .../TablesDB/Tables/Columns/Line/Update.php | 1 - .../TablesDB/Tables/Columns/Point/Create.php | 1 - .../TablesDB/Tables/Columns/Point/Update.php | 1 - .../Tables/Columns/Polygon/Create.php | 1 - .../Tables/Columns/Polygon/Update.php | 1 - .../Tables/Columns/Relationship/Create.php | 1 - .../Tables/Columns/Relationship/Update.php | 1 - .../TablesDB/Tables/Columns/String/Create.php | 1 - .../TablesDB/Tables/Columns/String/Update.php | 1 - .../TablesDB/Tables/Columns/URL/Create.php | 1 - .../TablesDB/Tables/Columns/URL/Update.php | 1 - .../Http/TablesDB/Tables/Columns/XList.php | 1 - .../Databases/Http/TablesDB/Tables/Create.php | 1 - .../Databases/Http/TablesDB/Tables/Delete.php | 1 - .../Databases/Http/TablesDB/Tables/Get.php | 1 - .../Http/TablesDB/Tables/Indexes/Create.php | 12 -- .../Http/TablesDB/Tables/Indexes/Delete.php | 1 - .../Http/TablesDB/Tables/Indexes/Get.php | 1 - .../Http/TablesDB/Tables/Indexes/XList.php | 1 - .../Http/TablesDB/Tables/Logs/XList.php | 1 - .../Http/TablesDB/Tables/Rows/Bulk/Delete.php | 1 - .../Http/TablesDB/Tables/Rows/Bulk/Update.php | 1 - .../Http/TablesDB/Tables/Rows/Bulk/Upsert.php | 1 - .../TablesDB/Tables/Rows/Column/Decrement.php | 1 - .../TablesDB/Tables/Rows/Column/Increment.php | 1 - .../Http/TablesDB/Tables/Rows/Create.php | 1 - .../Http/TablesDB/Tables/Rows/Delete.php | 1 - .../Http/TablesDB/Tables/Rows/Get.php | 1 - .../Http/TablesDB/Tables/Rows/Logs/XList.php | 1 - .../Http/TablesDB/Tables/Rows/Update.php | 1 - .../Http/TablesDB/Tables/Rows/Upsert.php | 1 - .../Http/TablesDB/Tables/Rows/XList.php | 1 - .../Databases/Http/TablesDB/Tables/Update.php | 1 - .../Http/TablesDB/Tables/Usage/Get.php | 1 - .../Databases/Http/TablesDB/Tables/XList.php | 1 - .../Http/TablesDB/Transactions/Create.php | 1 - .../Transactions/Operations/Create.php | 1 - .../Http/TablesDB/Transactions/Update.php | 1 - .../Databases/Http/TablesDB/Usage/Get.php | 1 - .../Databases/Http/TablesDB/Usage/XList.php | 1 - .../Functions/Http/Executions/Create.php | 25 ++- .../Functions/Http/Executions/Delete.php | 6 +- .../Modules/Functions/Http/Executions/Get.php | 10 +- .../Functions/Http/Executions/XList.php | 10 +- .../Functions/Http/Functions/Create.php | 8 +- .../Functions/Http/Functions/Delete.php | 6 +- .../Http/Functions/Deployment/Update.php | 10 +- .../Functions/Http/Functions/Update.php | 6 +- .../Modules/Functions/Http/Usage/Get.php | 5 +- .../Modules/Functions/Http/Usage/XList.php | 5 +- .../Functions/Http/Variables/Create.php | 6 +- .../Functions/Http/Variables/Delete.php | 6 +- .../Functions/Http/Variables/Update.php | 6 +- .../Modules/Functions/Workers/Builds.php | 16 +- .../Modules/Sites/Http/Deployments/Create.php | 8 +- .../Http/Deployments/Duplicate/Create.php | 6 +- .../Http/Deployments/Template/Create.php | 7 +- .../Sites/Http/Deployments/Vcs/Create.php | 6 +- .../Sites/Http/Sites/Deployment/Update.php | 8 +- .../Platform/Modules/Sites/Http/Usage/Get.php | 6 +- .../Modules/Sites/Http/Usage/XList.php | 5 +- .../Http/Tokens/Buckets/Files/Action.php | 17 +- .../Http/Tokens/Buckets/Files/Create.php | 11 +- .../Http/Tokens/Buckets/Files/XList.php | 6 +- src/Appwrite/Platform/Tasks/Migrate.php | 9 +- src/Appwrite/Platform/Tasks/ScheduleBase.php | 3 +- .../Platform/Tasks/StatsResources.php | 6 +- src/Appwrite/Platform/Workers/Deletes.php | 7 +- src/Appwrite/Platform/Workers/Functions.php | 2 + src/Appwrite/Platform/Workers/Migrations.php | 12 +- src/Appwrite/Utopia/Request.php | 9 +- src/Appwrite/Utopia/Request/Filter.php | 2 +- src/Appwrite/Utopia/Request/Filters/V20.php | 7 +- src/Appwrite/Utopia/Response.php | 9 +- .../DatabasesPermissionsGuestTest.php | 25 +-- .../DatabasesPermissionsGuestTest.php | 25 +-- .../Health/HealthCustomServerTest.php | 1 + tests/e2e/Services/Tokens/TokensBase.php | 8 +- tests/unit/Auth/AuthTest.php | 36 +--- .../unit/Messaging/MessagingChannelsTest.php | 18 +- 180 files changed, 868 insertions(+), 1248 deletions(-) diff --git a/app/cli.php b/app/cli.php index 0900926346..71b6464cb9 100644 --- a/app/cli.php +++ b/app/cli.php @@ -40,6 +40,8 @@ Config::setParam('runtimes', (new Runtimes('v5'))->getAll(supported: false)); // require controllers after overwriting runtimes require_once __DIR__ . '/controllers/general.php'; +Authorization::disable(); + CLI::setResource('register', fn () => $register); CLI::setResource('cache', function ($pools) { @@ -57,13 +59,7 @@ CLI::setResource('pools', function (Registry $register) { return $register->get('pools'); }, ['register']); -CLI::setResource('authorization', function () { - $authorization = new Authorization(); - $authorization->disable(); - return $authorization; -}, []); - -CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { +CLI::setResource('dbForPlatform', function ($pools, $cache) { $sleep = 3; $maxAttempts = 5; $attempts = 0; @@ -77,7 +73,6 @@ CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { $dbForPlatform = new Database($adapter, $cache); $dbForPlatform - ->setAuthorization($authorization) ->setNamespace('_console') ->setMetadata('host', \gethostname()) ->setMetadata('project', 'console'); @@ -102,7 +97,7 @@ CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { } return $dbForPlatform; -}, ['pools', 'cache', 'authorization']); +}, ['pools', 'cache']); CLI::setResource('console', function () { return new Document(Config::getParam('console')); @@ -113,10 +108,10 @@ CLI::setResource( fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false ); -CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, $authorization) { +CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) { $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools - return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) { + return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -149,7 +144,6 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $adapter = new DatabasePool($pools->get($dsn->getHost())); $database = new Database($adapter, $cache); - $databases[$dsn->getHost()] = $database; $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); @@ -166,18 +160,17 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform } $database - ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()); return $database; }; -}, ['pools', 'dbForPlatform', 'cache', 'authorization']); +}, ['pools', 'dbForPlatform', 'cache']); -CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { +CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database = null; - return function (?Document $project = null) use ($pools, $cache, $database, $authorization) { + return function (?Document $project = null) use ($pools, $cache, $database) { if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') { $database->setTenant((int)$project->getSequence()); return $database; @@ -187,7 +180,6 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio $database = new Database($adapter, $cache); $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK) @@ -200,7 +192,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio return $database; }; -}, ['pools', 'cache', 'authorization']); +}, ['pools', 'cache']); CLI::setResource('publisher', function (Group $pools) { return new BrokerPool(publisher: $pools->get('publisher')); }, ['pools']); diff --git a/app/config/storage/resource_limits.php b/app/config/storage/resource_limits.php index 43ed2b8b05..cfbcea5a47 100644 --- a/app/config/storage/resource_limits.php +++ b/app/config/storage/resource_limits.php @@ -3,6 +3,4 @@ use Utopia\Image\Image; use Utopia\System\System; -if (\class_exists('Imagick')) { - Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64))); -} +Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64))); diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index b6e1ebcc61..b7959bb6a9 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -192,10 +192,10 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc ; -$createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { +$createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails) { /** @var Utopia\Database\Document $user */ - $userFromRequest = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId)); + $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_INVALID_TOKEN); @@ -241,7 +241,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res $detector->getDevice() )); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session ->setAttribute('$permissions', [ @@ -250,7 +250,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res Permission::delete(Role::user($user->getId())), ])); - $authorization->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); + Authorization::skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId())); $dbForProject->purgeCachedDocument('users', $user->getId()); // Magic URL + Email OTP @@ -346,9 +346,8 @@ App::post('/v1/account') ->inject('user') ->inject('project') ->inject('dbForProject') - ->inject('authorization') ->inject('hooks') - ->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Hooks $hooks) { + ->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Hooks $hooks) { $email = \strtolower($email); if ('console' === $project->getId()) { @@ -439,9 +438,9 @@ App::post('/v1/account') ]); $user->removeAttribute('$sequence'); - $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -467,9 +466,9 @@ App::post('/v1/account') throw new Exception(Exception::USER_ALREADY_EXISTS); } - $authorization->removeRole(Role::guests()->toString()); - $authorization->addRole(Role::user($user->getId())->toString()); - $authorization->addRole(Role::users()->toString()); + Authorization::unsetRole(Role::guests()->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::users()->toString()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -930,8 +929,7 @@ App::post('/v1/account/sessions/email') ->inject('queueForEvents') ->inject('queueForMails') ->inject('hooks') - ->inject('authorization') - ->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks, Authorization $authorization) { + ->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks) { $email = \strtolower($email); $protocol = $request->getProtocol(); @@ -974,7 +972,7 @@ App::post('/v1/account/sessions/email') $detector->getDevice() )); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); // Re-hash if not using recommended algo if ($user->getAttribute('hash') !== Auth::DEFAULT_ALGO) { @@ -1066,8 +1064,7 @@ App::post('/v1/account/sessions/anonymous') ->inject('dbForProject') ->inject('geodb') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents, Authorization $authorization) { + ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents) { $protocol = $request->getProtocol(); if ('console' === $project->getId()) { @@ -1112,7 +1109,7 @@ App::post('/v1/account/sessions/anonymous') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$sequence'); - $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; @@ -1138,7 +1135,7 @@ App::post('/v1/account/sessions/anonymous') $detector->getDevice() )); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [ Permission::read(Role::user($user->getId())), @@ -1211,7 +1208,6 @@ App::post('/v1/account/sessions/token') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') - ->inject('authorization') ->action($createSession); App::get('/v1/account/sessions/oauth2/:provider') @@ -1404,8 +1400,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('dbForProject') ->inject('geodb') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, array $platforms, Document $devKey, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents, Authorization $authorization) use ($oauthDefaultSuccess) { + ->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, array $platforms, Document $devKey, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents) use ($oauthDefaultSuccess) { $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https'; $port = $request->getPort(); $callbackBase = $protocol . '://' . $request->getHostname(); @@ -1658,7 +1653,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ]); $user->removeAttribute('$sequence'); - $userDoc = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); + $userDoc = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), @@ -1677,8 +1672,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } } - $authorization->addRole(Role::user($user->getId())->toString()); - $authorization->addRole(Role::users()->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::users()->toString()); if (false === $user->getAttribute('status')) { // Account is blocked $failureRedirect(Exception::USER_BLOCKED); // User is in status blocked @@ -1749,7 +1744,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->updateDocument('users', $user->getId(), $user); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $state['success'] = URLParser::parse($state['success']); $query = URLParser::parseQuery($state['success']['query']); @@ -1771,7 +1766,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -1998,8 +1993,7 @@ App::post('/v1/account/tokens/magic-url') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') - ->inject('authorization') - ->action(function (string $userId, string $email, string $url, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { + ->action(function (string $userId, string $email, string $url, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -2072,7 +2066,7 @@ App::post('/v1/account/tokens/magic-url') ]); $user->removeAttribute('$sequence'); - $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); } $tokenSecret = Auth::tokenGenerator(Auth::TOKEN_LENGTH_MAGIC_URL); @@ -2089,7 +2083,7 @@ App::post('/v1/account/tokens/magic-url') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -2262,8 +2256,7 @@ App::post('/v1/account/tokens/email') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') - ->inject('authorization') - ->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { + ->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -2332,9 +2325,9 @@ App::post('/v1/account/tokens/email') ]); $user->removeAttribute('$sequence'); - $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); + $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2372,7 +2365,7 @@ App::post('/v1/account/tokens/email') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -2553,7 +2546,6 @@ App::put('/v1/account/sessions/magic-url') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') - ->inject('authorization') ->action($createSession); App::put('/v1/account/sessions/phone') @@ -2595,7 +2587,6 @@ App::put('/v1/account/sessions/phone') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') - ->inject('authorization') ->action($createSession); App::post('/v1/account/tokens/phone') @@ -2636,8 +2627,7 @@ App::post('/v1/account/tokens/phone') ->inject('timelimit') ->inject('queueForStatsUsage') ->inject('plan') - ->inject('authorization') - ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization) { + ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { if (empty(System::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -2687,9 +2677,9 @@ App::post('/v1/account/tokens/phone') ]); $user->removeAttribute('$sequence'); - $user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([ + $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2735,7 +2725,7 @@ App::post('/v1/account/tokens/phone') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $token = $dbForProject->createDocument('tokens', $token ->setAttribute('$permissions', [ @@ -3121,8 +3111,7 @@ App::patch('/v1/account/email') ->inject('queueForEvents') ->inject('project') ->inject('hooks') - ->inject('authorization') - ->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, Authorization $authorization) { + ->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks) { // passwordUpdate will be empty if the user has never set a password $passwordUpdate = $user->getAttribute('passwordUpdate'); @@ -3172,7 +3161,7 @@ App::patch('/v1/account/email') ->setAttribute('passwordUpdate', DateTime::now()); } - $target = $authorization->skip(fn () => $dbForProject->findOne('targets', [ + $target = Authorization::skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$email]), ])); @@ -3188,7 +3177,7 @@ App::patch('/v1/account/email') $oldTarget = $user->find('identifier', $oldEmail, 'targets'); if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { - $authorization->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); + Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); } $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Duplicate) { @@ -3230,8 +3219,7 @@ App::patch('/v1/account/phone') ->inject('queueForEvents') ->inject('project') ->inject('hooks') - ->inject('authorization') - ->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, Authorization $authorization) { + ->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks) { // passwordUpdate will be empty if the user has never set a password $passwordUpdate = $user->getAttribute('passwordUpdate'); @@ -3244,7 +3232,7 @@ App::patch('/v1/account/phone') $hooks->trigger('passwordValidator', [$dbForProject, $project, $password, &$user, false]); - $target = $authorization->skip(fn () => $dbForProject->findOne('targets', [ + $target = Authorization::skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), ])); @@ -3275,7 +3263,7 @@ App::patch('/v1/account/phone') $oldTarget = $user->find('identifier', $oldPhone, 'targets'); if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { - $authorization->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); + Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); } $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Duplicate $th) { @@ -3409,8 +3397,7 @@ App::post('/v1/account/recovery') ->inject('locale') ->inject('queueForMails') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $queueForMails, Event $queueForEvents, Authorization $authorization) { + ->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $queueForMails, Event $queueForEvents) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); @@ -3446,7 +3433,7 @@ App::post('/v1/account/recovery') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($profile->getId())->toString()); + Authorization::setRole(Role::user($profile->getId())->toString()); $recovery = $dbForProject->createDocument('tokens', $recovery ->setAttribute('$permissions', [ @@ -3588,8 +3575,7 @@ App::put('/v1/account/recovery') ->inject('project') ->inject('queueForEvents') ->inject('hooks') - ->inject('authorization') - ->action(function (string $userId, string $secret, string $password, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents, Hooks $hooks, Authorization $authorization) { + ->action(function (string $userId, string $secret, string $password, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents, Hooks $hooks) { $profile = $dbForProject->getDocument('users', $userId); if ($profile->isEmpty()) { @@ -3603,7 +3589,7 @@ App::put('/v1/account/recovery') throw new Exception(Exception::USER_INVALID_TOKEN); } - $authorization->addRole(Role::user($profile->getId())->toString()); + Authorization::setRole(Role::user($profile->getId())->toString()); $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); @@ -3701,8 +3687,7 @@ App::post('/v1/account/verifications/email') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') - ->inject('authorization') - ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, Authorization $authorization) { + ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); @@ -3731,7 +3716,7 @@ App::post('/v1/account/verifications/email') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $verification = $dbForProject->createDocument('tokens', $verification ->setAttribute('$permissions', [ @@ -3914,10 +3899,9 @@ App::put('/v1/account/verifications/email') ->inject('user') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Authorization $authorization) { + ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $profile = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId)); + $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -3930,7 +3914,7 @@ App::put('/v1/account/verifications/email') throw new Exception(Exception::USER_INVALID_TOKEN); } - $authorization->addRole(Role::user($profile->getId())->toString()); + Authorization::setRole(Role::user($profile->getId())->toString()); $profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('emailVerification', true)); @@ -3989,8 +3973,7 @@ App::post('/v1/account/verifications/phone') ->inject('timelimit') ->inject('queueForStatsUsage') ->inject('plan') - ->inject('authorization') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { if (empty(System::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -4029,7 +4012,7 @@ App::post('/v1/account/verifications/phone') 'ip' => $request->getIP(), ]); - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $verification = $dbForProject->createDocument('tokens', $verification ->setAttribute('$permissions', [ @@ -4134,10 +4117,9 @@ App::put('/v1/account/verifications/phone') ->inject('user') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Authorization $authorization) { + ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $profile = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId)); + $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -4149,7 +4131,7 @@ App::put('/v1/account/verifications/phone') throw new Exception(Exception::USER_INVALID_TOKEN); } - $authorization->addRole(Role::user($profile->getId())->toString()); + Authorization::setRole(Role::user($profile->getId())->toString()); $profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('phoneVerification', true)); @@ -5137,13 +5119,12 @@ App::post('/v1/account/targets/push') ->inject('request') ->inject('response') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) { + ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; - $provider = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); - $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); if (!$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); @@ -5218,10 +5199,9 @@ App::put('/v1/account/targets/:targetId/push') ->inject('request') ->inject('response') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) { + ->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { - $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); @@ -5284,9 +5264,8 @@ App::delete('/v1/account/targets/:targetId/push') ->inject('request') ->inject('response') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) { - $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + ->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject) { + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 544e22a0fa..d0cb3e554c 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -70,9 +70,9 @@ $avatarCallback = function (string $type, string $code, int $width, int $height, unset($image); }; -$getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, Authorization $authorization, ?Logger $logger) { +$getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, ?Logger $logger) { try { - $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); $sessions = $user->getAttribute('sessions', []); @@ -123,7 +123,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro ->setAttribute('providerRefreshToken', $refreshToken) ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); - $authorization->skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); + Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); $dbForProject->purgeCachedDocument('users', $user->getId()); } catch (Throwable $err) { @@ -131,7 +131,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro do { $previousAccessToken = $gitHubSession->getAttribute('providerAccessToken'); - $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); $sessions = $user->getAttribute('sessions', []); $gitHubSession = new Document(); @@ -841,9 +841,8 @@ App::get('/v1/cards/cloud') ->inject('contributors') ->inject('employees') ->inject('logger') - ->inject('authorization') - ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) { - $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { + $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -854,7 +853,7 @@ App::get('/v1/cards/cloud') $email = $user->getAttribute('email', ''); $createdAt = new \DateTime($user->getCreatedAt()); - $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger, $authorization); + $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger); $githubName = $gitHub['name'] ?? ''; $githubId = $gitHub['id'] ?? ''; @@ -1049,9 +1048,8 @@ App::get('/v1/cards/cloud-back') ->inject('contributors') ->inject('employees') ->inject('logger') - ->inject('authorization') - ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) { - $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { + $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -1061,7 +1059,7 @@ App::get('/v1/cards/cloud-back') $userId = $user->getId(); $email = $user->getAttribute('email', ''); - $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger, $authorization); + $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger); $githubId = $gitHub['id'] ?? ''; $isHero = \array_key_exists($email, $heroes); @@ -1128,9 +1126,8 @@ App::get('/v1/cards/cloud-og') ->inject('contributors') ->inject('employees') ->inject('logger') - ->inject('authorization') - ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) { - $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + ->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) { + $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); if ($user->isEmpty() && empty($mock)) { throw new Exception(Exception::USER_NOT_FOUND); @@ -1145,7 +1142,7 @@ App::get('/v1/cards/cloud-og') $email = $user->getAttribute('email', ''); $createdAt = new \DateTime($user->getCreatedAt()); - $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger, $authorization); + $gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger); $githubName = $gitHub['name'] ?? ''; $githubId = $gitHub['id'] ?? ''; diff --git a/app/controllers/api/graphql.php b/app/controllers/api/graphql.php index d0480225da..482b38d698 100644 --- a/app/controllers/api/graphql.php +++ b/app/controllers/api/graphql.php @@ -28,12 +28,11 @@ use Utopia\Validator\Text; App::init() ->groups(['graphql']) ->inject('project') - ->inject('authorization') - ->action(function (Document $project, Authorization $authorization) { + ->action(function (Document $project) { if ( array_key_exists('graphql', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['graphql'] - && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) + && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index dbbc667c94..58a0ffe42f 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -36,7 +36,6 @@ use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Cursor; @@ -1071,9 +1070,8 @@ App::get('/v1/messaging/providers') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -1099,7 +1097,7 @@ App::get('/v1/messaging/providers') } $providerId = $cursor->getValue(); - $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); @@ -2479,9 +2477,8 @@ App::get('/v1/messaging/topics') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -2507,7 +2504,7 @@ App::get('/v1/messaging/topics') } $topicId = $cursor->getValue(); - $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Topic '{$topicId}' for the 'cursor' value not found."); @@ -2783,27 +2780,29 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->param('targetId', '', new UID(), 'Target ID. The target ID to link to the specified Topic ID.') ->inject('queueForEvents') ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Response $response) { $subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId; - $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - if (!$authorization->isValid(new Input('subscribe', $topic->getAttribute('subscribe')))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + + $validator = new Authorization('subscribe'); + + if (!$validator->isValid($topic->getAttribute('subscribe'))) { + throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); } - $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - $user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber = new Document([ '$id' => $subscriberId, @@ -2836,7 +2835,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), }; - $authorization->skip(fn () => $dbForProject->increaseDocumentAttribute( + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute( 'topics', $topicId, $totalAttribute, @@ -2881,9 +2880,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -2894,7 +2892,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $queries[] = Query::search('search', $search); } - $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -2917,7 +2915,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') } $subscriberId = $cursor->getValue(); - $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Subscriber '{$subscriberId}' for the 'cursor' value not found."); @@ -2931,10 +2929,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers') throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null."); } - $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject, $authorization) { - return function () use ($subscriber, $dbForProject, $authorization) { - $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { + return function () use ($subscriber, $dbForProject) { + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); return $subscriber ->setAttribute('target', $target) @@ -3069,10 +3067,9 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') ->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.') ->param('subscriberId', '', new UID(), 'Subscriber ID.') ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Authorization $authorization, Response $response) { - $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) { + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -3084,8 +3081,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } - $target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber ->setAttribute('target', $target) @@ -3121,10 +3118,9 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') ->param('subscriberId', '', new UID(), 'Subscriber ID.') ->inject('queueForEvents') ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Authorization $authorization, Response $response) { - $topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId)); + ->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Response $response) { + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -3147,7 +3143,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), }; - $authorization->skip(fn () => $dbForProject->decreaseDocumentAttribute( + Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute( 'topics', $topicId, $totalAttribute, @@ -3704,9 +3700,8 @@ App::get('/v1/messaging/messages') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('dbForProject') - ->inject('authorization') ->inject('response') - ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) { + ->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { @@ -3732,7 +3727,7 @@ App::get('/v1/messaging/messages') } $messageId = $cursor->getValue(); - $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('messages', $messageId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('messages', $messageId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Message '{$messageId}' for the 'cursor' value not found."); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index f9d134db05..41b98ab333 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -1,6 +1,5 @@ <?php -use Appwrite\Auth\Auth; use Appwrite\Event\Event; use Appwrite\Event\Migration; use Appwrite\Extend\Exception; @@ -335,19 +334,26 @@ App::post('/v1/migrations/csv/imports') ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') - ->inject('authorization') ->inject('project') ->inject('deviceForFiles') ->inject('deviceForMigrations') ->inject('queueForEvents') ->inject('queueForMigrations') - ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Authorization $authorization, Document $project, Device $deviceForFiles, Device $deviceForMigrations, Event $queueForEvents, Migration $queueForMigrations) { - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - if ($internalFile && !$isPrivilegedUser) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - $bucket = $authorization->skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { + ->action(function ( + string $bucketId, + string $fileId, + string $resourceId, + bool $internalFile, + Response $response, + Database $dbForProject, + Database $dbForPlatform, + Document $project, + Device $deviceForFiles, + Device $deviceForMigrations, + Event $queueForEvents, + Migration $queueForMigrations + ) { + $bucket = Authorization::skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { if ($internalFile) { return $dbForPlatform->getDocument('buckets', 'default'); } @@ -358,7 +364,7 @@ App::post('/v1/migrations/csv/imports') throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = $authorization->skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } @@ -474,7 +480,6 @@ App::post('/v1/migrations/csv/exports') ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') - ->inject('authorization') ->inject('project') ->inject('queueForEvents') ->inject('queueForMigrations') @@ -492,7 +497,6 @@ App::post('/v1/migrations/csv/exports') Response $response, Database $dbForProject, Database $dbForPlatform, - Authorization $authorization, Document $project, Event $queueForEvents, Migration $queueForMigrations @@ -503,7 +507,7 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); } - $bucket = $authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'default')); + $bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'default')); if ($bucket->isEmpty()) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -516,12 +520,12 @@ App::post('/v1/migrations/csv/exports') throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index cda03f923a..a57675d3e8 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -45,10 +45,9 @@ App::get('/v1/project/usage') ->inject('response') ->inject('project') ->inject('dbForProject') - ->inject('authorization') ->inject('getLogsDB') ->inject('smsRates') - ->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, Authorization $authorization, callable $getLogsDB, array $smsRates) { + ->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, callable $getLogsDB, array $smsRates) { $stats = $total = $usage = []; $format = 'Y-m-d 00:00:00'; $firstDay = (new DateTime($startDate))->format($format); @@ -103,7 +102,7 @@ App::get('/v1/project/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - $authorization->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) { + Authorization::skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) { foreach ($metrics['total'] as $metric) { $db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject; @@ -287,7 +286,7 @@ App::get('/v1/project/usage') }, $dbForProject->find('functions')); // This total is includes free and paid SMS usage - $authPhoneTotal = $authorization->skip(fn () => $dbForProject->sum('stats', 'value', [ + $authPhoneTotal = Authorization::skip(fn () => $dbForProject->sum('stats', 'value', [ Query::equal('metric', [METRIC_AUTH_METHOD_PHONE]), Query::equal('period', ['1d']), Query::greaterThanEqual('time', $firstDay), @@ -295,7 +294,7 @@ App::get('/v1/project/usage') ])); // This estimate is only for paid SMS usage - $authPhoneMetrics = $authorization->skip(fn () => $dbForProject->find('stats', [ + $authPhoneMetrics = Authorization::skip(fn () => $dbForProject->find('stats', [ Query::startsWith('metric', METRIC_AUTH_METHOD_PHONE . '.'), Query::equal('period', ['1d']), Query::greaterThanEqual('time', $firstDay), diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index c2adc1e195..10fcbdb3d3 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -32,7 +32,6 @@ use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; @@ -434,20 +433,20 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('mode') ->inject('deviceForFiles') ->inject('deviceForLocal') - ->inject('authorization') - ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceForFiles, Device $deviceForLocal, Authorization $authorization) { + ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceForFiles, Device $deviceForLocal) { - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$authorization->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + $validator = new Authorization(Database::PERMISSION_CREATE); + if (!$validator->isValid($bucket->getCreate())) { + throw new Exception(Exception::USER_UNAUTHORIZED); } $allowedPermissions = [ @@ -470,7 +469,7 @@ App::post('/v1/storage/buckets/:bucketId/files') } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -483,7 +482,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization->hasRole($role)) { + if (!Authorization::isRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -703,10 +702,11 @@ App::post('/v1/storage/buckets/:bucketId/files') * However as with chunk upload even if we are updating, we are essentially creating a file * adding it's new chunk so we validate create permission instead of update */ - if (!$authorization->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + $validator = new Authorization(Database::PERMISSION_CREATE); + if (!$validator->isValid($bucket->getCreate())) { + throw new Exception(Exception::USER_UNAUTHORIZED); } - $file = $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } } else { if ($file->isEmpty()) { @@ -745,12 +745,13 @@ App::post('/v1/storage/buckets/:bucketId/files') * However as with chunk upload even if we are updating, we are essentially creating a file * adding it's new chunk so we validate create permission instead of update */ - if (!$authorization->isValid(new Input(Database::PERMISSION_CREATE, $bucket->getCreate()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + $validator = new Authorization(Database::PERMISSION_CREATE); + if (!$validator->isValid($bucket->getCreate())) { + throw new Exception(Exception::USER_UNAUTHORIZED); } try { - $file = $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -794,22 +795,22 @@ App::get('/v1/storage/buckets/:bucketId/files') ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->inject('mode') - ->action(function (string $bucketId, array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject, Authorization $authorization, string $mode) { - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->action(function (string $bucketId, array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject, string $mode) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } $queries = Query::parseQueries($queries); @@ -838,7 +839,7 @@ App::get('/v1/storage/buckets/:bucketId/files') if ($fileSecurity && !$valid) { $cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($cursorDocument->isEmpty()) { @@ -848,13 +849,15 @@ App::get('/v1/storage/buckets/:bucketId/files') $cursor->setValue($cursorDocument); } + $filterQueries = Query::groupByType($queries)['filters']; + try { if ($fileSecurity && !$valid) { $files = $dbForProject->find('bucket_' . $bucket->getSequence(), $queries); - $total = $includeTotal ? $dbForProject->count('bucket_' . $bucket->getSequence(), $queries, APP_LIMIT_COUNT) : 0; + $total = $includeTotal ? $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT) : 0; } else { - $files = $authorization->skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); - $total = $includeTotal ? $authorization->skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $queries, APP_LIMIT_COUNT)) : 0; + $files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries)); + $total = $includeTotal ? Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)) : 0; } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -893,28 +896,28 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->param('fileId', '', new UID(), 'File ID.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->inject('mode') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Authorization $authorization, string $mode) { - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($file->isEmpty()) { @@ -970,18 +973,17 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->inject('deviceForFiles') ->inject('deviceForLocal') ->inject('project') - ->inject('authorization') - ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Request $request, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal, Document $project, Authorization $authorization) { + ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Request $request, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal, Document $project) { if (!\extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } /* @type Document $bucket */ - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -993,20 +995,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($file->isEmpty()) { @@ -1124,11 +1127,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; //Do not update transformedAt if it's a console user - if (!Auth::isPrivilegedUser($authorization->getRoles())) { + if (!Auth::isPrivilegedUser(Authorization::getRoles())) { $transformedAt = $file->getAttribute('transformedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) { $file->setAttribute('transformedAt', DateTime::now()); - $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); + Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); } } @@ -1168,16 +1171,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->inject('request') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->inject('mode') ->inject('resourceToken') ->inject('deviceForFiles') - ->action(function (string $bucketId, string $fileId, ?string $token, Request $request, Response $response, Database $dbForProject, Authorization $authorization, string $mode, Document $resourceToken, Device $deviceForFiles) { + ->action(function (string $bucketId, string $fileId, ?string $token, Request $request, Response $response, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) { /* @type Document $bucket */ - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1185,20 +1187,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($file->isEmpty()) { @@ -1332,13 +1335,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->inject('mode') ->inject('resourceToken') ->inject('deviceForFiles') - ->inject('authorization') - ->action(function (string $bucketId, string $fileId, ?string $token, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles, Authorization $authorization) { + ->action(function (string $bucketId, string $fileId, ?string $token, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) { /* @type Document $bucket */ - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1346,20 +1348,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); if (!$fileSecurity && !$valid && !$isToken) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { /* @type Document $file */ - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($file->isEmpty()) { @@ -1488,14 +1491,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->inject('project') ->inject('mode') ->inject('deviceForFiles') - ->inject('authorization') - ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Database $dbForPlatform, Document $project, string $mode, Device $deviceForFiles, Authorization $authorization) { + ->action(function (string $bucketId, string $fileId, string $jwt, Response $response, Request $request, Database $dbForProject, Database $dbForPlatform, Document $project, string $mode, Device $deviceForFiles) { $decoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0); try { $decoded = $decoder->decode($jwt); } catch (JWTException) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } if ( @@ -1503,21 +1505,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $decoded['bucketId'] !== $bucketId || $decoded['fileId'] !== $fileId ) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } $isInternal = $decoded['internal'] ?? false; $dbForProject = $isInternal ? $dbForPlatform : $dbForProject; - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } @@ -1525,6 +1527,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $mimes = Config::getParam('storage-mimes'); $path = $file->getAttribute('path', ''); + if (!$deviceForFiles->exists($path)) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); } @@ -1661,26 +1664,26 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('user') ->inject('mode') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $queueForEvents, Authorization $authorization) { + ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $queueForEvents) { - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); + $validator = new Authorization(Database::PERMISSION_UPDATE); + $valid = $validator->isValid($bucket->getUpdate()); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for update - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1694,7 +1697,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ]); // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -1707,7 +1710,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization->hasRole($role)) { + if (!Authorization::isRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -1728,7 +1731,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $file = $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file); } else { - $file = $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1776,34 +1779,33 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('mode') ->inject('deviceForFiles') ->inject('queueForDeletes') - ->inject('authorization') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceForFiles, Delete $queueForDeletes, Authorization $authorization) { - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceForFiles, Delete $queueForDeletes) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_DELETE, $bucket->getDelete())); + $validator = new Authorization(Database::PERMISSION_DELETE); + $valid = $validator->isValid($bucket->getDelete()); if (!$fileSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for delete - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } // Make sure we don't delete the file before the document permission check occurs - $validFile = $authorization->isValid(new Input(Database::PERMISSION_DELETE, $file->getDelete())); - if ($fileSecurity && !$valid && !$validFile) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + if ($fileSecurity && !$valid && !$validator->isValid($file->getDelete())) { + throw new Exception(Exception::USER_UNAUTHORIZED); } $deviceDeleted = false; @@ -1827,7 +1829,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $deleted = $authorization->skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId)); + $deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId)); } } catch (NotFoundException) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -1872,8 +1874,7 @@ App::get('/v1/storage/usage') ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $range, Response $response, Database $dbForProject, Authorization $authorization) { + ->action(function (string $range, Response $response, Database $dbForProject) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -1885,7 +1886,7 @@ App::get('/v1/storage/usage') ]; $total = []; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), @@ -1963,8 +1964,7 @@ App::get('/v1/storage/:bucketId/usage') ->inject('project') ->inject('dbForProject') ->inject('getLogsDB') - ->inject('authorization') - ->action(function (string $bucketId, string $range, Response $response, Document $project, Database $dbForProject, callable $getLogsDB, Authorization $authorization) { + ->action(function (string $bucketId, string $range, Response $response, Document $project, Database $dbForProject, callable $getLogsDB) { $dbForLogs = call_user_func($getLogsDB, $project); $bucket = $dbForProject->getDocument('buckets', $bucketId); @@ -1982,7 +1982,7 @@ App::get('/v1/storage/:bucketId/usage') str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED), ]; - $authorization->skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $db = ($metric === str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED)) ? $dbForLogs diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 4b8c543e5d..554ef6f4fe 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -84,17 +84,16 @@ App::post('/v1/teams') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('authorization') ->inject('queueForEvents') - ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { + ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $isAppUser = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAppUser = Auth::isAppUser(Authorization::getRoles()); $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; try { - $team = $authorization->skip(fn () => $dbForProject->createDocument('teams', new Document([ + $team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([ '$id' => $teamId, '$permissions' => [ Permission::read(Role::team($teamId)), @@ -490,7 +489,6 @@ App::post('/v1/teams/:teamId/memberships') ->inject('project') ->inject('user') ->inject('dbForProject') - ->inject('authorization') ->inject('locale') ->inject('queueForMails') ->inject('queueForMessaging') @@ -498,9 +496,9 @@ App::post('/v1/teams/:teamId/memberships') ->inject('timelimit') ->inject('queueForStatsUsage') ->inject('plan') - ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Authorization $authorization, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { - $isAppUser = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) { + $isAppUser = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $url = htmlentities($url); if (empty($url)) { @@ -575,50 +573,53 @@ App::post('/v1/teams/:teamId/memberships') $emailCanonical = null; } + $userId = ID::unique(); + + $userDocument = new Document([ + '$id' => $userId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user($userId)), + Permission::update(Role::user($userId)), + Permission::delete(Role::user($userId)), + ], + 'email' => empty($email) ? null : $email, + 'phone' => empty($phone) ? null : $phone, + 'emailVerification' => false, + 'status' => true, + // TODO: Set password empty? + 'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS), + 'hash' => Auth::DEFAULT_ALGO, + 'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS, + /** + * Set the password update time to 0 for users created using + * team invite and OAuth to allow password updates without an + * old password + */ + 'passwordUpdate' => null, + 'registration' => DateTime::now(), + 'reset' => false, + 'name' => $name, + 'prefs' => new \stdClass(), + 'sessions' => null, + 'tokens' => null, + 'memberships' => null, + 'search' => implode(' ', [$userId, $email, $name]), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), + 'emailIsFree' => $emailCanonical?->isFree(), + ]); + try { - $userId = ID::unique(); - $invitee = $authorization->skip(fn () => $dbForProject->createDocument('users', new Document([ - '$id' => $userId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user($userId)), - Permission::update(Role::user($userId)), - Permission::delete(Role::user($userId)), - ], - 'email' => empty($email) ? null : $email, - 'phone' => empty($phone) ? null : $phone, - 'emailVerification' => false, - 'status' => true, - // TODO: Set password empty? - 'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS), - 'hash' => Auth::DEFAULT_ALGO, - 'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS, - /** - * Set the password update time to 0 for users created using - * team invite and OAuth to allow password updates without an - * old password - */ - 'passwordUpdate' => null, - 'registration' => DateTime::now(), - 'reset' => false, - 'name' => $name, - 'prefs' => new \stdClass(), - 'sessions' => null, - 'tokens' => null, - 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]), - 'emailCanonical' => $emailCanonical?->getCanonical(), - 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical?->isCorporate(), - 'emailIsDisposable' => $emailCanonical?->isDisposable(), - 'emailIsFree' => $emailCanonical?->isFree(), - ]))); + $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', $userDocument)); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } } - $isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner'); + $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team'); @@ -654,11 +655,11 @@ App::post('/v1/teams/:teamId/memberships') ]); $membership = ($isPrivilegedUser || $isAppUser) ? - $authorization->skip(fn () => $dbForProject->createDocument('memberships', $membership)) : + Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)) : $dbForProject->createDocument('memberships', $membership); if ($isPrivilegedUser || $isAppUser) { - $authorization->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); } } elseif ($membership->getAttribute('confirm') === false) { @@ -671,7 +672,7 @@ App::post('/v1/teams/:teamId/memberships') } $membership = ($isPrivilegedUser || $isAppUser) ? - $authorization->skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) : + Authorization::skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) : $dbForProject->updateDocument('memberships', $membership->getId(), $membership); } else { throw new Exception(Exception::MEMBERSHIP_ALREADY_CONFIRMED); @@ -858,8 +859,7 @@ App::get('/v1/teams/:teamId/memberships') ->inject('response') ->inject('project') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject, Authorization $authorization) { + ->action(function (string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -929,7 +929,7 @@ App::get('/v1/teams/:teamId/memberships') 'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true, ]; - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -1000,8 +1000,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') ->inject('response') ->inject('project') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject, Authorization $authorization) { + ->action(function (string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject) { $team = $dbForProject->getDocument('teams', $teamId); @@ -1021,7 +1020,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') 'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true, ]; - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -1100,9 +1099,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->inject('user') ->inject('project') ->inject('dbForProject') - ->inject('authorization') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -1119,9 +1117,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::USER_NOT_FOUND); } - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $isAppUser = Auth::isAppUser($authorization->getRoles()); - $isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner'); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAppUser = Auth::isAppUser(Authorization::getRoles()); + $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); if ($project->getId() === 'console') { // Quick check: fetch up to 2 owners to determine if only one exists @@ -1202,11 +1200,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('authorization') ->inject('project') ->inject('geodb') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Document $project, Reader $geodb, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Reader $geodb, Event $queueForEvents) { $protocol = $request->getProtocol(); $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -1215,7 +1212,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') throw new Exception(Exception::MEMBERSHIP_NOT_FOUND); } - $team = $authorization->skip(fn () => $dbForProject->getDocument('teams', $teamId)); + $team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -1251,11 +1248,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->setAttribute('confirm', true) ; - $authorization->skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); + Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); // Create session for the user if not logged in if (!$hasSession) { - $authorization->addRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::user($user->getId())->toString()); $detector = new Detector($request->getUserAgent('UNKNOWN')); $record = $geodb->get($request->getIP()); @@ -1283,7 +1280,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $session = $dbForProject->createDocument('sessions', $session); - $authorization->addRole(Role::user($userId)->toString()); + Authorization::setRole(Role::user($userId)->toString()); if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); @@ -1316,7 +1313,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $dbForProject->purgeCachedDocument('users', $user->getId()); - $authorization->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); $queueForEvents ->setParam('userId', $user->getId()) @@ -1360,9 +1357,8 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->inject('project') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) { $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -1420,7 +1416,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $dbForProject->purgeCachedDocument('users', $profile->getId()); if ($membership->getAttribute('confirm')) { // Count only confirmed members - $authorization->skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); + Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); } $queueForEvents diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 3fd570b03f..a8570c3079 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2647,8 +2647,8 @@ App::get('/v1/users/usage') ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') - ->action(function (string $range, Response $response, Database $dbForProject, Authorization $authorization) { + ->inject('register') + ->action(function (string $range, Response $response, Database $dbForProject) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -2658,7 +2658,7 @@ App::get('/v1/users/usage') METRIC_SESSIONS, ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $count => $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 4703e3a296..2ac6cd0b26 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -72,7 +72,7 @@ use Utopia\VCS\Exception\RepositoryNotFound; use function Swoole\Coroutine\batch; -$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForPlatform, Authorization $authorization, Build $queueForBuilds, callable $getProjectDB, Request $request) { +$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForPlatform, Build $queueForBuilds, callable $getProjectDB, Request $request) { $errors = []; foreach ($repositories as $repository) { try { @@ -83,12 +83,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId } $projectId = $repository->getAttribute('projectId'); - $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); $dbForProject = $getProjectDB($project); $resourceCollection = $resourceType === "function" ? 'functions' : 'sites'; $resourceId = $repository->getAttribute('resourceId'); - $resource = $authorization->skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId)); + $resource = Authorization::skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId)); $resourceInternalId = $resource->getSequence(); $deploymentId = ID::unique(); @@ -137,7 +137,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = ''; if (!empty($providerPullRequestId) && $resource->getAttribute('providerSilentMode', false) === false) { - $latestComment = $authorization->skip(fn () => $dbForPlatform->findOne('vcsComments', [ + $latestComment = Authorization::skip(fn () => $dbForPlatform->findOne('vcsComments', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::equal('providerPullRequestId', [$providerPullRequestId]), Query::orderDesc('$createdAt'), @@ -176,7 +176,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment())); } finally { - $authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); + Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); } } } else { @@ -187,7 +187,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId if (!empty($latestCommentId)) { $teamId = $project->getAttribute('teamId', ''); - $latestComment = $authorization->skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([ + $latestComment = Authorization::skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([ '$id' => ID::unique(), '$permissions' => [ Permission::read(Role::team(ID::custom($teamId))), @@ -208,7 +208,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId } } } elseif (!empty($providerBranch)) { - $latestComments = $authorization->skip(fn () => $dbForPlatform->find('vcsComments', [ + $latestComments = Authorization::skip(fn () => $dbForPlatform->find('vcsComments', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::equal('providerBranch', [$providerBranch]), Query::orderDesc('$createdAt'), @@ -247,7 +247,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment())); } finally { - $authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); + Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); } } } @@ -290,7 +290,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $commands[] = $resource->getAttribute('commands', ''); } - $deployment = $authorization->skip(fn () => $dbForProject->createDocument('deployments', new Document([ + $deployment = Authorization::skip(fn () => $dbForProject->createDocument('deployments', new Document([ '$id' => $deploymentId, '$permissions' => [ Permission::read(Role::any()), @@ -330,7 +330,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId ->setAttribute('latestDeploymentInternalId', $deployment->getSequence()) ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); - $authorization->skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource)); + Authorization::skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource)); if ($resource->getCollection() === 'sites') { $projectId = $project->getId(); @@ -340,7 +340,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = ID::unique() . "." . $sitesDomain; $ruleId = md5($domain); $previewRuleId = $ruleId; - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -373,7 +373,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -404,7 +404,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $domain = "commit-" . substr($providerCommitHash, 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -456,7 +456,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId if ($lockAcquired) { // Wrap in try/finally to ensure lock file gets deleted try { - $rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId)); + $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId)); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https'; $previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : ''; @@ -468,7 +468,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()); } } finally { - $authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); + Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId)); } } } @@ -1462,11 +1462,10 @@ App::post('/v1/vcs/github/events') ->inject('request') ->inject('response') ->inject('dbForPlatform') - ->inject('authorization') ->inject('getProjectDB') ->inject('queueForBuilds') ->action( - function (GitHub $github, Request $request, Response $response, Database $dbForPlatform, Authorization $authorization, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { + function (GitHub $github, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { $payload = $request->getRawPayload(); $signatureRemote = $request->getHeader('x-hub-signature-256', ''); $signatureLocal = System::getEnv('_APP_VCS_GITHUB_WEBHOOK_SECRET', ''); @@ -1502,14 +1501,14 @@ App::post('/v1/vcs/github/events') $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); //find resourceId from relevant resources table - $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::limit(100), ])); // create new deployment only on push (not committed by us) and not when branch is created or deleted if ($providerCommitAuthorEmail !== APP_VCS_GITHUB_EMAIL && !$providerBranchCreated && !$providerBranchDeleted) { - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); } } elseif ($event == $github::EVENT_INSTALLATION) { if ($parsedPayload["action"] == "deleted") { @@ -1522,16 +1521,16 @@ App::post('/v1/vcs/github/events') ]); foreach ($installations as $installation) { - $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('installationInternalId', [$installation->getSequence()]), Query::limit(1000) ])); foreach ($repositories as $repository) { - $authorization->skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId())); + Authorization::skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId())); } - $authorization->skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId())); + Authorization::skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId())); } } } elseif ($event == $github::EVENT_PULL_REQUEST) { @@ -1560,12 +1559,12 @@ App::post('/v1/vcs/github/events') $providerCommitAuthor = $commitDetails["commitAuthor"] ?? ''; $providerCommitMessage = $commitDetails["commitMessage"] ?? ''; - $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::orderDesc('$createdAt') ])); - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); } elseif ($parsedPayload["action"] == "closed") { // Allowed external contributions cleanup @@ -1574,7 +1573,7 @@ App::post('/v1/vcs/github/events') $external = $parsedPayload["external"] ?? true; if ($external) { - $repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [ + $repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [ Query::equal('providerRepositoryId', [$providerRepositoryId]), Query::orderDesc('$createdAt') ])); @@ -1585,7 +1584,7 @@ App::post('/v1/vcs/github/events') if (\in_array($providerPullRequestId, $providerPullRequestIds)) { $providerPullRequestIds = \array_diff($providerPullRequestIds, [$providerPullRequestId]); $repository = $repository->setAttribute('providerPullRequestIds', $providerPullRequestIds); - $repository = $authorization->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); + $repository = Authorization::skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); } } } @@ -1773,17 +1772,16 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor ->inject('response') ->inject('project') ->inject('dbForPlatform') - ->inject('authorization') ->inject('getProjectDB') ->inject('queueForBuilds') - ->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForPlatform, Authorization $authorization, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { + ->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForPlatform, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) { $installation = $dbForPlatform->getDocument('installations', $installationId); if ($installation->isEmpty()) { throw new Exception(Exception::INSTALLATION_NOT_FOUND); } - $repository = $authorization->skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [ + $repository = Authorization::skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [ Query::equal('projectInternalId', [$project->getSequence()]) ])); @@ -1800,7 +1798,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor // TODO: Delete from array when PR is closed - $repository = $authorization->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); + $repository = Authorization::skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository)); $privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); $githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID'); @@ -1824,7 +1822,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor $providerBranch = \explode(':', $pullRequestResponse['head']['label'])[1] ?? ''; $providerCommitHash = $pullRequestResponse['head']['sha'] ?? ''; - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, '', '', '', '', $providerCommitHash, '', '', '', '', $providerPullRequestId, true, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerCommitHash, $providerPullRequestId, true, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); $response->noContent(); }); diff --git a/app/controllers/general.php b/app/controllers/general.php index 6790d3c67d..e0435cd499 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -57,7 +57,7 @@ Config::setParam('domainVerification', false); Config::setParam('cookieDomain', 'localhost'); Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE); -function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Authorization $authorization, ?Key $apiKey) +function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { $host = $request->getHostname() ?? ''; if (!empty($previewHostname)) { @@ -66,9 +66,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw // TODO: @christyjacob remove once we migrate the rules in 1.7.x if (System::getEnv('_APP_RULES_FORMAT') === 'md5') { - $rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', md5($host))); + $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($host))); } else { - $rule = $authorization->skip( + $rule = Authorization::skip( fn () => $dbForPlatform->find('rules', [ Query::equal('domain', [$host]), Query::limit(1) @@ -109,7 +109,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $projectId = $rule->getAttribute('projectId'); - $project = $authorization->skip( + $project = Authorization::skip( fn () => $dbForPlatform->getDocument('projects', $projectId) ); @@ -117,7 +117,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } /** @@ -156,7 +156,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw /** @var Document $deployment */ if (!empty($rule->getAttribute('deploymentId', ''))) { - $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); + $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); } else { // 1.6.x DB schema compatibility // TODO: Make sure deploymentId is never empty, and remove this code @@ -170,15 +170,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw // Document of site or function $resource = $resourceType === 'function' ? - $authorization->skip(fn () => $dbForProject->getDocument('functions', $resourceId)) : - $authorization->skip(fn () => $dbForProject->getDocument('sites', $resourceId)); + Authorization::skip(fn () => $dbForProject->getDocument('functions', $resourceId)) : + Authorization::skip(fn () => $dbForProject->getDocument('sites', $resourceId)); // ID of active deployments // Attempts to use attribute from both schemas (1.6 and 1.7) $activeDeploymentId = $resource->getAttribute('deploymentId', $resource->getAttribute('deployment', '')); // Get deployment document, as intended originally - $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId)); + $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId)); } if ($deployment->getAttribute('resourceType', '') === 'functions') { @@ -197,8 +197,8 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $resource = $type === 'function' ? - $authorization->skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) : - $authorization->skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', ''))); + Authorization::skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) : + Authorization::skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', ''))); $isPreview = $type === 'function' ? false : ($rule->getAttribute('trigger', '') !== 'manual'); @@ -240,7 +240,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw $userExists = false; $userId = $payload['userId'] ?? ''; if (!empty($userId)) { - $user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId)); + $user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId)); if (!$user->isEmpty() && $user->getAttribute('status', false)) { $userExists = true; } @@ -253,7 +253,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw } $membershipExists = false; - $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); if (!$project->isEmpty() && isset($user)) { $teamId = $project->getAttribute('teamId', ''); $membership = $user->find('teamId', $teamId, 'memberships'); @@ -864,8 +864,7 @@ App::init() ->inject('apiKey') ->inject('httpReferrer') ->inject('httpReferrerSafe') - ->inject('authorization') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $platforms, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe, Authorization $authorization) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $platforms, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, string $httpReferrer, string $httpReferrerSafe) { /* * Appwrite Router */ @@ -873,7 +872,7 @@ App::init() $mainDomain = System::getEnv('_APP_DOMAIN', ''); // Only run Router when external domain if ($host !== $mainDomain || !empty($previewHostname)) { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -924,7 +923,7 @@ App::init() } elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) { Console::warning('Skipping SSL certificates generation on ACME challenge.'); } else { - $authorization->disable(); + Authorization::disable(); $envDomain = System::getEnv('_APP_DOMAIN', ''); $mainDomain = null; @@ -994,7 +993,7 @@ App::init() } $domains[$domain->get()] = true; - $authorization->reset(); // ensure authorization is re-enabled + Authorization::reset(); // ensure authorization is re-enabled } Config::setParam('domains', $domains); } @@ -1130,8 +1129,7 @@ App::options() ->inject('project') ->inject('devKey') ->inject('apiKey') - ->inject('authorization') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey, Authorization $authorization) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey) { /* * Appwrite Router */ @@ -1139,7 +1137,7 @@ App::options() $mainDomain = System::getEnv('_APP_DOMAIN', ''); // Only run Router when external domain if ($host !== $mainDomain || !empty($previewHostname)) { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -1180,8 +1178,7 @@ App::error() ->inject('log') ->inject('queueForStatsUsage') ->inject('devKey') - ->inject('authorization') - ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage, Document $devKey, Authorization $authorization) { + ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage) { $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); $route = $utopia->getRoute(); $class = \get_class($error); @@ -1263,7 +1260,7 @@ App::error() * If not a publishable error, track usage stats. Publishable errors are >= 500 or those explicitly marked as publish=true in errors.php */ if (!$publish && $project->getId() !== 'console') { - if (!Auth::isPrivilegedUser($authorization->getRoles())) { + if (!Auth::isPrivilegedUser(Authorization::getRoles())) { $fileSize = 0; $file = $request->getFiles('file'); if (!empty($file)) { @@ -1325,7 +1322,7 @@ App::error() $log->addExtra('file', $error->getFile()); $log->addExtra('line', $error->getLine()); $log->addExtra('trace', $error->getTraceAsString()); - $log->addExtra('roles', $authorization->getRoles()); + $log->addExtra('roles', Authorization::getRoles()); $action = 'UNKNOWN_NAMESPACE.UNKNOWN.METHOD'; if (!empty($sdk)) { @@ -1448,8 +1445,7 @@ App::get('/robots.txt') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('apiKey') - ->inject('authorization') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey, Authorization $authorization) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { $host = $request->getHostname() ?? ''; $consoleDomain = System::getEnv('_APP_CONSOLE_DOMAIN', ''); $mainDomain = System::getEnv('_APP_DOMAIN', ''); @@ -1458,7 +1454,7 @@ App::get('/robots.txt') $template = new View(__DIR__ . '/../views/general/robots.phtml'); $response->text($template->render(false)); } else { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -1483,8 +1479,7 @@ App::get('/humans.txt') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('apiKey') - ->inject('authorization') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey, Authorization $authorization) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { $host = $request->getHostname() ?? ''; $consoleDomain = System::getEnv('_APP_CONSOLE_DOMAIN', ''); $mainDomain = System::getEnv('_APP_DOMAIN', ''); @@ -1493,7 +1488,7 @@ App::get('/humans.txt') $template = new View(__DIR__ . '/../views/general/humans.phtml'); $response->text($template->render(false)); } else { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $authorization, $apiKey)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) { $utopia->getRoute()?->label('router', true); } } @@ -1577,8 +1572,7 @@ App::get('/v1/ping') ->inject('project') ->inject('dbForPlatform') ->inject('queueForEvents') - ->inject('authorization') - ->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents, Authorization $authorization) { + ->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents) { if ($project->isEmpty() || $project->getId() === 'console') { throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND); } @@ -1590,7 +1584,7 @@ App::get('/v1/ping') ->setAttribute('pingCount', $pingCount) ->setAttribute('pingedAt', $pingedAt); - $authorization->skip(function () use ($dbForPlatform, $project) { + Authorization::skip(function () use ($dbForPlatform, $project) { $dbForPlatform->updateDocument('projects', $project->getId(), $project); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 911c8b110d..6a146f2bdc 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -29,7 +29,6 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Queue\Publisher; use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; @@ -233,8 +232,7 @@ App::init() ->inject('mode') ->inject('team') ->inject('apiKey') - ->inject('authorization') - ->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) { + ->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey) { $route = $utopia->getRoute(); if (System::getEnv('_APP_EDITION', 'self-hosted') === 'self-hosted' && str_starts_with($route->getPath(), '/v1/backups')) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Database Backups are available on Appwrite Cloud'); @@ -266,7 +264,7 @@ App::init() if ($apiKey->getRole() === Auth::USER_ROLE_APPS) { // Disable authorization checks for API keys - $authorization->setDefaultStatus(false); + Authorization::setDefaultStatus(false); $user = new Document([ '$id' => '', @@ -339,14 +337,14 @@ App::init() $scopes = \array_merge($scopes, $roles[$role]['scopes']); } - $authorization->setDefaultStatus(false); // Cancel security segmentation for admin users. + Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. } $scopes = \array_unique($scopes); - $authorization->addRole($role); - foreach (Auth::getRoles($user, $authorization) as $authRole) { - $authorization->addRole($authRole); + Authorization::setRole($role); + foreach (Auth::getRoles($user) as $authRole) { + Authorization::setRole($authRole); } // Update project last activity @@ -354,7 +352,7 @@ App::init() $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } } @@ -389,7 +387,7 @@ App::init() if ( array_key_exists($namespace, $project->getAttribute('services', [])) && !$project->getAttribute('services', [])[$namespace] - && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) + && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) ) { throw new Exception(Exception::GENERAL_SERVICE_DISABLED); } @@ -449,15 +447,14 @@ App::init() ->inject('plan') ->inject('devKey') ->inject('telemetry') - ->inject('authorization') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, Authorization $authorization) use ($usageDatabaseListener, $eventDatabaseListener) { + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry) use ($usageDatabaseListener, $eventDatabaseListener) { $route = $utopia->getRoute(); if ( array_key_exists('rest', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['rest'] - && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) + && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } @@ -487,7 +484,7 @@ App::init() $closestLimit = null; - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -587,10 +584,10 @@ App::init() if ($useCache) { $route = $utopia->match($request); $isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview'; - $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser($authorization->getRoles()); + $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser(Authorization::getRoles()); $key = $request->cacheIdentifier(); - $cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $cache = new Cache( new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); @@ -607,10 +604,10 @@ App::init() if ($type === 'bucket' && (!$isImageTransformation || !$isDisabled)) { $bucketId = $parts[1] ?? null; - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence(); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); @@ -621,7 +618,8 @@ App::init() } $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead())); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); if (!$fileSecurity && !$valid && !$isToken) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -632,7 +630,7 @@ App::init() if ($fileSecurity && !$valid && !$isToken) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) { @@ -643,11 +641,11 @@ App::init() throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } //Do not update transformedAt if it's a console user - if (!Auth::isPrivilegedUser($authorization->getRoles())) { + if (!Auth::isPrivilegedUser(Authorization::getRoles())) { $transformedAt = $file->getAttribute('transformedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) { $file->setAttribute('transformedAt', DateTime::now()); - $authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); + Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file)); } } } @@ -743,8 +741,7 @@ App::shutdown() ->inject('queueForWebhooks') ->inject('queueForRealtime') ->inject('dbForProject') - ->inject('authorization') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization) use ($parseLabel) { + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject) use ($parseLabel) { $responsePayload = $response->getPayload(); @@ -870,11 +867,11 @@ App::shutdown() $key = $request->cacheIdentifier(); $signature = md5($data['payload']); - $cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $accessedAt = $cacheLog->getAttribute('accessedAt', 0); $now = DateTime::now(); if ($cacheLog->isEmpty()) { - $authorization->skip(fn () => $dbForProject->createDocument('cache', new Document([ + Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([ '$id' => $key, 'resource' => $resource, 'resourceType' => $resourceType, @@ -884,7 +881,7 @@ App::shutdown() ]))); } elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) { $cacheLog->setAttribute('accessedAt', $now); - $authorization->skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog)); + Authorization::skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog)); // Overwrite the file every APP_CACHE_UPDATE seconds to update the file modified time that is used in the TTL checks in cache->load() $cache->save($key, $data['payload']); } @@ -896,7 +893,7 @@ App::shutdown() } if ($project->getId() !== 'console') { - if (!Auth::isPrivilegedUser($authorization->getRoles())) { + if (!Auth::isPrivilegedUser(Authorization::getRoles())) { $fileSize = 0; $file = $request->getFiles('file'); if (!empty($file)) { diff --git a/app/controllers/shared/api/auth.php b/app/controllers/shared/api/auth.php index 0e3c89c19a..ecabc641ec 100644 --- a/app/controllers/shared/api/auth.php +++ b/app/controllers/shared/api/auth.php @@ -36,8 +36,7 @@ App::init() ->inject('request') ->inject('project') ->inject('geodb') - ->inject('authorization') - ->action(function (App $utopia, Request $request, Document $project, Reader $geodb, Authorization $authorization) { + ->action(function (App $utopia, Request $request, Document $project, Reader $geodb) { $denylist = System::getEnv('_APP_CONSOLE_COUNTRIES_DENYLIST', ''); if (!empty($denylist && $project->getId() === 'console')) { $countries = explode(',', $denylist); @@ -50,8 +49,8 @@ App::init() $route = $utopia->match($request); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); - $isAppUser = Auth::isAppUser($authorization->getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + $isAppUser = Auth::isAppUser(Authorization::getRoles()); if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs return; diff --git a/app/http.php b/app/http.php index 568571fad2..1bd3e97e69 100644 --- a/app/http.php +++ b/app/http.php @@ -25,6 +25,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Logger\Log; use Utopia\Logger\Log\User; use Utopia\Pools\Group; @@ -258,9 +259,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg createDatabase($app, 'getLogsDB', 'logs', $collections['logs'], $pools); // create appwrite database, `dbForPlatform` is a direct access call. - createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections, $app) { - $authorization = $app->getResource('authorization'); - + createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections) { if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) { $audit = new Audit($dbForPlatform); $audit->setup(); @@ -319,9 +318,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes); } - if ($authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { + if (Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { Console::info(" └── Creating screenshots bucket..."); - $authorization->skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ + Authorization::skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ '$id' => ID::custom('screenshots'), '$collection' => ID::custom('buckets'), 'name' => 'Screenshots', @@ -336,7 +335,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg 'search' => 'buckets Screenshots', ]))); - $bucket = $authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); + $bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); Console::info(" └── Creating files collection for screenshots bucket..."); $files = $collections['buckets']['files'] ?? []; @@ -364,7 +363,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg 'orders' => $index['orders'], ]), $files['indexes']); - $authorization->skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes)); + Authorization::skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes)); } }); @@ -455,12 +454,8 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool App::setResource('pools', fn () => $pools); try { - $authorization = $app->getResource('authorization'); - - $request->setAuthorization($authorization); - $response->setAuthorization($authorization); - $authorization->cleanRoles(); - $authorization->addRole(Role::any()->toString()); + Authorization::cleanRoles(); + Authorization::setRole(Role::any()->toString()); $app->run($request, $response); } catch (\Throwable $th) { @@ -502,7 +497,7 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool $log->addExtra('file', $th->getFile()); $log->addExtra('line', $th->getLine()); $log->addExtra('trace', $th->getTraceAsString()); - $log->addExtra('roles', isset($authorization) ? $authorization->getRoles() : []); + $log->addExtra('roles', Authorization::getRoles()); $sdk = $route->getLabel("sdk", false); @@ -561,7 +556,7 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) { /** @var Utopia\Database\Database $dbForPlatform */ $dbForPlatform = $app->getResource('dbForPlatform'); - Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $domains, &$lastSyncUpdate, $app) { + Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $domains, &$lastSyncUpdate) { try { $time = DateTime::now(); $limit = 1000; @@ -578,8 +573,7 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) { } $results = []; try { - $authorization = $app->getResource('authorization'); - $results = $authorization->skip(fn () => $dbForPlatform->find('rules', $queries)); + $results = Authorization::skip(fn () => $dbForPlatform->find('rules', $queries)); } catch (Throwable $th) { Console::error($th->getMessage()); } diff --git a/app/init/database/filters.php b/app/init/database/filters.php index c065bf0d82..c4cfd1ac81 100644 --- a/app/init/database/filters.php +++ b/app/init/database/filters.php @@ -4,6 +4,7 @@ use Appwrite\OpenSSL\OpenSSL; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\System\System; Database::addFilter( @@ -175,7 +176,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return $database->getAuthorization()->skip(fn () => $database->find('sessions', [ + return Authorization::skip(fn () => $database->find('sessions', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), ])); @@ -188,7 +189,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return $database->getAuthorization()->skip(fn () => $database + return Authorization::skip(fn () => $database ->find('tokens', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -202,7 +203,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return $database->getAuthorization()->skip(fn () => $database + return Authorization::skip(fn () => $database ->find('challenges', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -216,7 +217,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return $database->getAuthorization()->skip(fn () => $database + return Authorization::skip(fn () => $database ->find('authenticators', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -230,7 +231,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return $database->getAuthorization()->skip(fn () => $database + return Authorization::skip(fn () => $database ->find('memberships', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -330,7 +331,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - return $database->getAuthorization()->skip(fn () => $database + return Authorization::skip(fn () => $database ->find('targets', [ Query::equal('userInternalId', [$document->getSequence()]), Query::limit(APP_LIMIT_SUBQUERY) @@ -344,7 +345,7 @@ Database::addFilter( return; }, function (mixed $value, Document $document, Database $database) { - $targetIds = $database->getAuthorization()->skip(fn () => \array_map( + $targetIds = Authorization::skip(fn () => \array_map( fn ($document) => $document->getAttribute('targetInternalId'), $database->find('subscribers', [ Query::equal('topicInternalId', [$document->getSequence()]), diff --git a/app/init/resources.php b/app/init/resources.php index 8b111e950c..0892da8a82 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -152,7 +152,7 @@ App::setResource('queueForMigrations', function (Publisher $publisher) { App::setResource('queueForStatsResources', function (Publisher $publisher) { return new StatsResources($publisher); }, ['publisher']); -App::setResource('platforms', function (Request $request, Document $console, Document $project, Database $dbForPlatform, Authorization $authorization) { +App::setResource('platforms', function (Request $request, Document $console, Document $project, Database $dbForPlatform) { $console->setAttribute('platforms', [ // Always allow current host '$collection' => ID::custom('platforms'), 'name' => 'Current Host', @@ -200,9 +200,9 @@ App::setResource('platforms', function (Request $request, Document $console, Doc // Safe if rule with same project ID exists if (!empty($origin)) { if (System::getEnv('_APP_RULES_FORMAT') === 'md5') { - $rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? ''))); + $rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? ''))); } else { - $rule = $authorization->skip( + $rule = Authorization::skip( fn () => $dbForPlatform->find('rules', [ Query::equal('domain', [$origin]), Query::limit(1) @@ -224,18 +224,17 @@ App::setResource('platforms', function (Request $request, Document $console, Doc ...$console->getAttribute('platforms', []), ...$project->getAttribute('platforms', []), ]; -}, ['request', 'console', 'project', 'dbForPlatform', 'authorization']); +}, ['request', 'console', 'project', 'dbForPlatform']); -App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForPlatform, $authorization) { +App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForPlatform) { /** @var Appwrite\Utopia\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Document $project */ /** @var Utopia\Database\Database $dbForProject */ /** @var Utopia\Database\Database $dbForPlatform */ - /** @var Utopia\Database\Authorization $authorization */ /** @var string $mode */ - $authorization->setDefaultStatus(true); + Authorization::setDefaultStatus(true); Auth::setCookieName('a_session_' . $project->getId()); @@ -299,7 +298,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons // if (APP_MODE_ADMIN === $mode) { // if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) { - // $authorization->setDefaultStatus(false); // Cancel security segmentation for admin users. + // Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. // } else { // $user = new Document([]); // } @@ -337,9 +336,9 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $dbForPlatform->setMetadata('user', $user->getId()); return $user; -}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform', 'authorization']); +}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform']); -App::setResource('project', function ($dbForPlatform, $request, $console, $authorization) { +App::setResource('project', function ($dbForPlatform, $request, $console) { /** @var Appwrite\Utopia\Request $request */ /** @var Utopia\Database\Database $dbForPlatform */ /** @var Utopia\Database\Document $console */ @@ -350,10 +349,10 @@ App::setResource('project', function ($dbForPlatform, $request, $console, $autho return $console; } - $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); return $project; -}, ['dbForPlatform', 'request', 'console', 'authorization']); +}, ['dbForPlatform', 'request', 'console']); App::setResource('session', function (Document $user) { if ($user->isEmpty()) { @@ -380,11 +379,7 @@ App::setResource('console', function () { return new Document(Config::getParam('console')); }, []); -App::setResource('authorization', function () { - return new Authorization(); -}, []); - -App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project, Authorization $authorization) { +App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -400,7 +395,6 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform $database = new Database($adapter, $cache); $database - ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()) ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) @@ -421,15 +415,13 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform } return $database; -}, ['pools', 'dbForPlatform', 'cache', 'project', 'authorization']); - -App::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authorization $authorization) { +}, ['pools', 'dbForPlatform', 'cache', 'project']); +App::setResource('dbForPlatform', function (Group $pools, Cache $cache) { $adapter = new DatabasePool($pools->get('console')); $database = new Database($adapter, $cache); $database - ->setAuthorization($authorization) ->setNamespace('_console') ->setMetadata('host', \gethostname()) ->setMetadata('project', 'console') @@ -437,12 +429,12 @@ App::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authoriz ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); return $database; -}, ['pools', 'cache', 'authorization']); +}, ['pools', 'cache']); -App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, Authorization $authorization) { +App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) { $databases = []; - return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) { + return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -454,9 +446,8 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $dsn = new DSN('mysql://' . $project->getAttribute('database')); } - $configure = (function (Database $database) use ($project, $dsn, $authorization) { + $configure = (function (Database $database) use ($project, $dsn) { $database - ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()) ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) @@ -490,12 +481,12 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform return $database; }; -}, ['pools', 'dbForPlatform', 'cache', 'authorization']); +}, ['pools', 'dbForPlatform', 'cache']); -App::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { +App::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database = null; - return function (?Document $project = null) use ($pools, $cache, $authorization, &$database) { + return function (?Document $project = null) use ($pools, $cache, &$database) { if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') { $database->setTenant((int) $project->getSequence()); return $database; @@ -505,7 +496,6 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio $database = new Database($adapter, $cache); $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) @@ -518,7 +508,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio return $database; }; -}, ['pools', 'cache', 'authorization']); +}, ['pools', 'cache']); App::setResource('telemetry', fn () => new NoTelemetry()); @@ -712,7 +702,7 @@ App::setResource('promiseAdapter', function ($register) { return $register->get('promiseAdapter'); }, ['register']); -App::setResource('schema', function ($utopia, $dbForProject, $authorization) { +App::setResource('schema', function ($utopia, $dbForProject) { $complexity = function (int $complexity, array $args) { $queries = Query::parseQueries($args['queries'] ?? []); @@ -722,8 +712,8 @@ App::setResource('schema', function ($utopia, $dbForProject, $authorization) { return $complexity * $limit; }; - $attributes = function (int $limit, int $offset) use ($dbForProject, $authorization) { - $attrs = $authorization->skip(fn () => $dbForProject->find('attributes', [ + $attributes = function (int $limit, int $offset) use ($dbForProject) { + $attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [ Query::limit($limit), Query::offset($offset), ])); @@ -797,7 +787,7 @@ App::setResource('schema', function ($utopia, $dbForProject, $authorization) { $urls, $params, ); -}, ['utopia', 'dbForProject', 'authorization']); +}, ['utopia', 'dbForProject']); App::setResource('contributors', function () { $path = 'app/config/contributors.json'; @@ -843,7 +833,7 @@ App::setResource('smsRates', function () { return []; }); -App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform, Authorization $authorization) { +App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform) { $devKey = $request->getHeader('x-appwrite-dev-key', $request->getParam('devKey', '')); // Check if given key match project's development keys @@ -862,7 +852,7 @@ App::setResource('devKey', function (Request $request, Document $project, array $accessedAt = $key->getAttribute('accessedAt', 0); if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) { $key->setAttribute('accessedAt', DatabaseDateTime::now()); - $authorization->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); $dbForPlatform->purgeCachedDocument('projects', $project->getId()); } @@ -879,14 +869,14 @@ App::setResource('devKey', function (Request $request, Document $project, array /** Update access time as well */ $key->setAttribute('accessedAt', DatabaseDateTime::now()); - $key = $authorization->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); + $key = Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key)); $dbForPlatform->purgeCachedDocument('projects', $project->getId()); } } return $key; -}, ['request', 'project', 'servers', 'dbForPlatform', 'authorization']); +}, ['request', 'project', 'servers', 'dbForPlatform']); -App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request, Authorization $authorization) { +App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request) { $teamInternalId = ''; if ($project->getId() !== 'console') { $teamInternalId = $project->getAttribute('teamInternalId', ''); @@ -896,7 +886,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A if (str_starts_with($path, '/v1/projects/:projectId')) { $uri = $request->getURI(); $pid = explode('/', $uri)[3]; - $p = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $pid)); + $p = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $pid)); $teamInternalId = $p->getAttribute('teamInternalId', ''); } elseif ($path === '/v1/projects') { $teamId = $request->getParam('teamId', ''); @@ -905,7 +895,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A return new Document([]); } - $team = $authorization->skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); + $team = Authorization::skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); return $team; } } @@ -914,14 +904,14 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A return new Document([]); } - $team = $authorization->skip(function () use ($dbForPlatform, $teamInternalId) { + $team = Authorization::skip(function () use ($dbForPlatform, $teamInternalId) { return $dbForPlatform->findOne('teams', [ Query::equal('$sequence', [$teamInternalId]), ]); }); return $team; -}, ['project', 'dbForPlatform', 'utopia', 'request', 'authorization']); +}, ['project', 'dbForPlatform', 'utopia', 'request']); App::setResource( 'isResourceBlocked', @@ -959,7 +949,7 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key App::setResource('executor', fn () => new Executor()); -App::setResource('resourceToken', function ($project, $dbForProject, $request, Authorization $authorization) { +App::setResource('resourceToken', function ($project, $dbForProject, $request) { $tokenJWT = $request->getParam('token'); if (!empty($tokenJWT) && !$project->isEmpty()) { // JWT authentication @@ -976,7 +966,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request, A return new Document([]); } - $token = $authorization->skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId)); + $token = Authorization::skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId)); if ($token->isEmpty()) { return new Document([]); @@ -994,7 +984,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request, A } return match ($token->getAttribute('resourceType')) { - TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject, $authorization) { + TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject) { $sequences = explode(':', $token->getAttribute('resourceInternalId')); $ids = explode(':', $token->getAttribute('resourceId')); @@ -1005,7 +995,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request, A $accessedAt = $token->getAttribute('accessedAt', 0); if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_RESOURCE_TOKEN_ACCESS)) > $accessedAt) { $token->setAttribute('accessedAt', DatabaseDateTime::now()); - $authorization->skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token)); + Authorization::skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token)); } return new Document([ @@ -1020,7 +1010,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request, A }; } return new Document([]); -}, ['project', 'dbForProject', 'request', 'authorization']); +}, ['project', 'dbForProject', 'request']); App::setResource('httpReferrer', function (Request $request): string { $referrer = $request->getReferer(); @@ -1053,6 +1043,6 @@ App::setResource('httpReferrerSafe', function (Request $request, string $httpRef return $referrer; }, ['request', 'httpReferrer', 'platforms', 'dbForPlatform', 'project', 'utopia']); -App::setResource('transactionState', function (Database $dbForProject, Authorization $authorization) { - return new TransactionState($dbForProject, $authorization); -}, ['dbForProject', 'authorization']); +App::setResource('transactionState', function (Database $dbForProject) { + return new TransactionState($dbForProject); +}, ['dbForProject']); diff --git a/app/realtime.php b/app/realtime.php index 75aa625348..e18ab8e10d 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -28,6 +28,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; use Utopia\Logger\Log; use Utopia\Pools\Group; @@ -298,7 +299,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume 'value' => '{}' ]); - $statsDocument = $database->getAuthorization()->skip(fn () => $database->createDocument('realtime', $document)); + $statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document)); break; } catch (Throwable) { Console::warning("Collection not ready. Retrying connection ({$attempts})..."); @@ -328,7 +329,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume ->setAttribute('timestamp', DateTime::now()) ->setAttribute('value', json_encode($payload)); - $database->getAuthorization()->skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); + Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); } catch (Throwable $th) { $logError($th, "updateWorkerDocument"); } @@ -359,7 +360,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $payload = []; - $list = $database->getAuthorization()->skip(fn () => $database->find('realtime', [ + $list = Authorization::skip(fn () => $database->find('realtime', [ Query::greaterThan('timestamp', DateTime::addSeconds(new \DateTime(), -15)), ])); @@ -453,11 +454,12 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); $consoleDatabase = getConsoleDB(); - $project = $consoleDatabase->getAuthorization()->skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); $database = getProjectDB($project); $user = $database->getDocument('users', $userId); - $roles = Auth::getRoles($user, $database->getAuthorization()); + + $roles = Auth::getRoles($user); $channels = $realtime->connections[$connection]['channels']; $realtime->unsubscribe($connection); @@ -513,7 +515,6 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, try { /** @var Document $project */ $project = $app->getResource('project'); - $authorization = $app->getResource('authorization'); /* * Project Check @@ -525,7 +526,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, if ( array_key_exists('realtime', $project->getAttribute('apis', [])) && !$project->getAttribute('apis', [])['realtime'] - && !(Auth::isPrivilegedUser($authorization->getRoles()) || Auth::isAppUser($authorization->getRoles())) + && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED); } @@ -562,7 +563,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, throw new Exception(Exception::REALTIME_POLICY_VIOLATION, $originValidator->getDescription()); } - $roles = Auth::getRoles($user, $authorization); + $roles = Auth::getRoles($user); $channels = Realtime::convertChannels($request->getQuery('channels', []), $user->getId()); @@ -636,8 +637,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $database = getConsoleDB(); if ($projectId !== 'console') { - $project = $database->getAuthorization()->skip(fn () => $database->getDocument('projects', $projectId)); - $database = getProjectDB($project, $database->getAuthorization()); + $project = Authorization::skip(fn () => $database->getDocument('projects', $projectId)); + $database = getProjectDB($project); } else { $project = null; } @@ -691,7 +692,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Session is not valid.'); } - $roles = Auth::getRoles($user, $database->getAuthorization()); + $roles = Auth::getRoles($user); $channels = Realtime::convertChannels(array_flip($realtime->connections[$connection]['channels']), $user->getId()); $realtime->subscribe($realtime->connections[$connection]['projectId'], $connection, $roles, $channels); diff --git a/app/worker.php b/app/worker.php index ef04ffec05..60f44ab33f 100644 --- a/app/worker.php +++ b/app/worker.php @@ -45,28 +45,19 @@ use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; use Utopia\Telemetry\Adapter\None as NoTelemetry; +Authorization::disable(); Runtime::enableCoroutine(); Server::setResource('register', fn () => $register); -Server::setResource('authorization', function () { - $authorization = new Authorization(); - $authorization->disable(); - return $authorization; -}, []); - -Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, Authorization $authorization) { +Server::setResource('dbForPlatform', function (Cache $cache, Registry $register) { $pools = $register->get('pools'); $adapter = new DatabasePool($pools->get('console')); $dbForPlatform = new Database($adapter, $cache); - - $dbForPlatform - ->setAuthorization($authorization) - ->setNamespace('_console'); - + $dbForPlatform->setNamespace('_console'); return $dbForPlatform; -}, ['cache', 'register', 'authorization']); +}, ['cache', 'register']); Server::setResource('project', function (Message $message, Database $dbForPlatform) { $payload = $message->getPayload() ?? []; @@ -79,7 +70,7 @@ Server::setResource('project', function (Message $message, Database $dbForPlatfo return $dbForPlatform->getDocument('projects', $project->getId()); }, ['message', 'dbForPlatform']); -Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForPlatform, Authorization $authorization) { +Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForPlatform) { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -110,17 +101,15 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, ->setNamespace('_' . $project->getSequence()); } - $database - ->setAuthorization($authorization) - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); + $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); return $database; -}, ['cache', 'register', 'message', 'project', 'dbForPlatform', 'authorization']); +}, ['cache', 'register', 'message', 'project', 'dbForPlatform']); -Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, Authorization $authorization) { +Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) { $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools - return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases): Database { + return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases): Database { if ($project->isEmpty() || $project->getId() === 'console') { return $dbForPlatform; } @@ -134,7 +123,7 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf if (isset($databases[$dsn->getHost()])) { $database = $databases[$dsn->getHost()]; - $database->setAuthorization($authorization); + $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); if (\in_array($dsn->getHost(), $sharedTables)) { @@ -171,17 +160,15 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf ->setNamespace('_' . $project->getSequence()); } - $database - ->setAuthorization($authorization) - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); + $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); return $database; }; -}, ['pools', 'dbForPlatform', 'cache', 'authorization']); +}, ['pools', 'dbForPlatform', 'cache']); -Server::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { +Server::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database = null; - return function (?Document $project = null) use ($pools, $cache, $database, $authorization) { + return function (?Document $project = null) use ($pools, $cache, $database) { if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') { $database->setTenant((int)$project->getSequence()); return $database; @@ -191,7 +178,6 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache, Authoriza $database = new Database($adapter, $cache); $database - ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER) @@ -204,7 +190,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache, Authoriza return $database; }; -}, ['pools', 'cache', 'authorization']); +}, ['pools', 'cache']); Server::setResource('abuseRetention', function () { return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400); // 1 day @@ -492,8 +478,7 @@ $worker ->inject('log') ->inject('pools') ->inject('project') - ->inject('authorization') - ->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project, Authorization $authorization) use ($worker, $queueName) { + ->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project) use ($worker, $queueName) { $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); if ($logger) { @@ -509,7 +494,7 @@ $worker $log->addExtra('file', $error->getFile()); $log->addExtra('line', $error->getLine()); $log->addExtra('trace', $error->getTraceAsString()); - $log->addExtra('roles', $authorization->getRoles()); + $log->addExtra('roles', Authorization::getRoles()); $isProduction = System::getEnv('_APP_ENV', 'development') === 'production'; $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); diff --git a/composer.json b/composer.json index 1cff497d08..62abce9ca2 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.13.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "4.*", + "utopia-php/database": "3.*", "utopia-php/detector": "0.2.*", "utopia-php/domains": "0.9.*", "utopia-php/emails": "0.6.*", diff --git a/composer.lock b/composer.lock index 163bdb5bd9..b29b19c3bf 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": "3b502f78f5e31f2ea7b4c69e3301283a", + "content-hash": "ad28b7155175986191bd19bbcd13d623", "packages": [ { "name": "adhocore/jwt", @@ -3551,21 +3551,21 @@ }, { "name": "utopia-php/audit", - "version": "1.0.3", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "15656acfddb9d6f03c395b73673fc66c793c10a5" + "reference": "8c17065c2473d4ca799f65585ca74eb53e1be211" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/15656acfddb9d6f03c395b73673fc66c793c10a5", - "reference": "15656acfddb9d6f03c395b73673fc66c793c10a5", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/8c17065c2473d4ca799f65585ca74eb53e1be211", + "reference": "8c17065c2473d4ca799f65585ca74eb53e1be211", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "4.*" + "utopia-php/database": "*" }, "require-dev": { "laravel/pint": "1.*", @@ -3592,9 +3592,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/1.0.3" + "source": "https://github.com/utopia-php/audit/tree/1.0.2" }, - "time": "2025-11-04T11:27:42+00:00" + "time": "2025-10-20T07:14:26+00:00" }, { "name": "utopia-php/cache", @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "4.3.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "fe7a1326ad623609e65587fe8c01a630a7075fee" + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/fe7a1326ad623609e65587fe8c01a630a7075fee", - "reference": "fe7a1326ad623609e65587fe8c01a630a7075fee", + "url": "https://api.github.com/repos/utopia-php/database/zipball/e10b4faa4f3a3ef30a5f6d76acdb605469924aec", + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/4.3.0" + "source": "https://github.com/utopia-php/database/tree/3.4.0" }, - "time": "2025-11-14T03:43:10+00:00" + "time": "2025-11-13T06:34:20+00:00" }, { "name": "utopia-php/detector", @@ -4460,16 +4460,16 @@ }, { "name": "utopia-php/migration", - "version": "1.3.4", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "81e1be6ff3257d4768aa7483cf64628836244a09" + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/81e1be6ff3257d4768aa7483cf64628836244a09", - "reference": "81e1be6ff3257d4768aa7483cf64628836244a09", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/731b3a963c58c30e0b2368695d57a7e8fcb7455c", + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c", "shasum": "" }, "require": { @@ -4478,7 +4478,7 @@ "ext-openssl": "*", "php": ">=8.1", "utopia-php/console": "0.0.*", - "utopia-php/database": "4.*", + "utopia-php/database": "3.*", "utopia-php/dsn": "0.2.*", "utopia-php/storage": "0.18.*" }, @@ -4509,9 +4509,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.3.4" + "source": "https://github.com/utopia-php/migration/tree/1.3.3" }, - "time": "2025-11-04T11:28:50+00:00" + "time": "2025-10-28T04:02:08+00:00" }, { "name": "utopia-php/mongo", diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index b6676a2843..9af5045fa4 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -453,11 +453,11 @@ class Auth * @param Document $user * @return array<string> */ - public static function getRoles(Document $user, Authorization $authorization): array + public static function getRoles(Document $user): array { $roles = []; - if (!self::isPrivilegedUser($authorization->getRoles()) && !self::isAppUser($authorization->getRoles())) { + if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) { if ($user->getId()) { $roles[] = Role::user($user->getId())->toString(); $roles[] = Role::users()->toString(); diff --git a/src/Appwrite/Databases/TransactionState.php b/src/Appwrite/Databases/TransactionState.php index 8e098774e6..23dc6fc2e9 100644 --- a/src/Appwrite/Databases/TransactionState.php +++ b/src/Appwrite/Databases/TransactionState.php @@ -20,12 +20,10 @@ use Utopia\Database\Validator\Authorization; class TransactionState { private Database $dbForProject; - private Authorization $authorization; - /** @var Authorization $authorization */ - public function __construct(Database $dbForProject, Authorization $authorization) + + public function __construct(Database $dbForProject) { $this->dbForProject = $dbForProject; - $this->authorization = $authorization; } @@ -344,12 +342,12 @@ class TransactionState */ private function getTransactionState(string $transactionId): array { - $transaction = $this->authorization->skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId)); + $transaction = Authorization::skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId)); if ($transaction->isEmpty() || $transaction->getAttribute('status') !== 'pending') { return []; } - $operations = $this->authorization->skip(fn () => $this->dbForProject->find('transactionLogs', [ + $operations = Authorization::skip(fn () => $this->dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX) diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 4d2db6a3dc..588b193df4 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -99,6 +99,8 @@ abstract class Migration public function __construct() { + Authorization::disable(); + Authorization::setDefaultStatus(false); $this->collections = Config::getParam('collections', []); @@ -126,7 +128,6 @@ abstract class Migration Document $project, Database $dbForProject, Database $dbForPlatform, - Authorization $authorization, ?callable $getProjectDB = null ): self { $this->project = $project; @@ -134,9 +135,6 @@ abstract class Migration $this->dbForPlatform = $dbForPlatform; $this->getProjectDB = $getProjectDB; - $authorization->disable(); - $authorization->setDefaultStatus(false); - return $this; } diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 8ff5d88dd4..a538eb1497 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -142,7 +142,7 @@ class Base extends Action return $deployment; } - public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, Authorization $authorization, string $referenceType = 'branch', string $reference = ''): Document + public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document { $deploymentId = ID::unique(); $providerInstallationId = $installation->getAttribute('providerInstallationId', ''); @@ -238,7 +238,7 @@ class Base extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -264,7 +264,7 @@ class Base extends Action $domain = "commit-" . substr($commitDetails['commitHash'], 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -301,7 +301,7 @@ class Base extends Action $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php index a0f8e9421e..b67a42adb1 100644 --- a/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php +++ b/src/Appwrite/Platform/Modules/Console/Http/Resources/Get.php @@ -59,7 +59,6 @@ class Get extends Action ->param('type', '', new WhiteList(['rules']), 'Resource type.') ->inject('response') ->inject('dbForPlatform') - ->inject('authorization') ->callback($this->action(...)); } @@ -67,8 +66,7 @@ class Get extends Action string $value, string $type, Response $response, - Database $dbForPlatform, - Authorization $authorization + Database $dbForPlatform ) { if ($type === 'rules') { $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); @@ -126,7 +124,7 @@ class Get extends Action throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.'); } - $document = $authorization->skip(fn () => $dbForPlatform->findOne('rules', [ + $document = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal('domain', [$value]), ])); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php index 6c5305f299..48124e2a11 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php @@ -292,7 +292,7 @@ abstract class Action extends UtopiaAction }; } - protected function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): Document + protected function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): Document { $key = $attribute->getAttribute('key'); $type = $attribute->getAttribute('type', ''); @@ -310,7 +310,7 @@ abstract class Action extends UtopiaAction throw new Exception($this->getSpatialTypeNotSupportedException()); } - $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -371,7 +371,7 @@ abstract class Action extends UtopiaAction \in_array($attribute->getAttribute('type'), Database::SPATIAL_TYPES) && $attribute->getAttribute('required') ) { - $hasData = !$authorization->skip(fn () => $dbForProject + $hasData = !Authorization::skip(fn () => $dbForProject ->findOne('database_' . $db->getSequence() . '_collection_' . $collection->getSequence())) ->isEmpty(); @@ -472,9 +472,9 @@ abstract class Action extends UtopiaAction return $attribute; } - protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, Authorization $authorization, string $type, int $size = null, string $filter = null, string|bool|int|float|array $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document + protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, string $type, int $size = null, string $filter = null, string|bool|int|float|array $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document { - $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php index 4f233fcdb4..8dfe80a390 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -70,11 +69,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -83,7 +81,7 @@ class Create extends Action 'required' => $required, 'default' => $default, 'array' => $array, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php index 27a3622fe2..ddb01ff011 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Boolean/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,11 +68,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -81,7 +79,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_BOOLEAN, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php index d96314855c..d0f45dc664 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; @@ -71,11 +70,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute( $databaseId, @@ -92,8 +90,7 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents, - $authorization + $queueForEvents ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php index bdf38a5087..1a30a09867 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; @@ -70,11 +69,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,7 +80,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_DATETIME, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php index 07ab604a5a..eb51044323 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php @@ -67,13 +67,12 @@ class Delete extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php index eed105e583..9f4c38d490 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Create.php @@ -13,7 +13,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -71,11 +70,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute( $databaseId, @@ -92,8 +90,7 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents, - $authorization + $queueForEvents ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php index d9cbb5ba80..59a0490e6f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -70,11 +69,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,7 +80,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_EMAIL, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php index fb82dfd478..d2ccf9f972 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php @@ -13,7 +13,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -74,11 +73,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { if (!is_null($default) && !\in_array($default, $elements, true)) { throw new Exception($this->getInvalidValueException(), 'Default value not found in elements'); @@ -100,8 +98,7 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents, - $authorization + $queueForEvents ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php index 31984d5f43..560107dd38 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -72,11 +71,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -84,7 +82,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_ENUM, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php index 6cd158631f..f48348c192 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Create.php @@ -13,7 +13,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -75,11 +74,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $min ??= -PHP_FLOAT_MAX; $max ??= PHP_FLOAT_MAX; @@ -102,7 +100,7 @@ class Create extends Action 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, 'formatOptions' => ['min' => $min, 'max' => $max], - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $formatOptions = $attribute->getAttribute('formatOptions', []); if (!empty($formatOptions)) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php index 6d7d22caf8..99ac992b9e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Float/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -72,11 +71,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -84,7 +82,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_FLOAT, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php index d31b17667e..91fa3582f7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Get.php @@ -68,13 +68,12 @@ class Get extends Action ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php index 9c5e3707d5..af3ed99bdf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -71,11 +70,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute( $databaseId, @@ -92,8 +90,7 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents, - $authorization + $queueForEvents ); $response diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php index 2ee0f1a35b..a757ed47d1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/IP/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -70,11 +69,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,7 +80,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_IP, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php index 99492c6950..5e147c771d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Create.php @@ -13,7 +13,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -75,11 +74,10 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $min ??= \PHP_INT_MIN; $max ??= \PHP_INT_MAX; @@ -104,7 +102,7 @@ class Create extends Action 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_INT_RANGE, 'formatOptions' => ['min' => $min, 'max' => $max], - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $formatOptions = $attribute->getAttribute('formatOptions', []); if (!empty($formatOptions)) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php index 419f09a4b3..6d3858992b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Integer/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -72,11 +71,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -84,7 +82,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_INTEGER, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php index 7a92b3e13d..f691fc29cf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -70,18 +69,17 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_LINESTRING, 'required' => $required, 'default' => $default - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php index 904209443f..8ef2f96ec2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Line/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -70,11 +69,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,7 +80,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_LINESTRING, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php index 9aff7cba34..aae715ba1e 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -70,18 +69,17 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_POINT, 'required' => $required, 'default' => $default, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php index 55cadc4ca8..62f35ad2a7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Point/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -70,11 +69,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,7 +80,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_POINT, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php index bc3dd75ace..6fbbd46d2c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -70,18 +69,17 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_POLYGON, 'required' => $required, 'default' => $default, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php index 1dcca49d99..dba83d44d5 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Polygon/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Spatial; use Utopia\Database\Validator\UID; @@ -70,11 +69,10 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -82,7 +80,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_POLYGON, default: $default, required: $required, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php index 30c49911b0..6fc27a9836 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Create.php @@ -83,16 +83,15 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $relatedCollectionId, string $type, bool $twoWay, ?string $key, ?string $twoWayKey, string $onDelete, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $relatedCollectionId, string $type, bool $twoWay, ?string $key, ?string $twoWayKey, string $onDelete, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { $key ??= $relatedCollectionId; $twoWayKey ??= $collectionId; - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -151,7 +150,7 @@ class Create extends Action 'twoWayKey' => $twoWayKey, 'onDelete' => $onDelete, ] - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); foreach ($attribute->getAttribute('options', []) as $k => $option) { $attribute->setAttribute($k, $option); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php index 8623f7cb17..f9f1d6f3ab 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -72,7 +71,6 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } @@ -84,8 +82,7 @@ class Update extends Action ?string $newKey, UtopiaResponse $response, Database $dbForProject, - Event $queueForEvents, - Authorization $authorization + Event $queueForEvents ): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -93,7 +90,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_RELATIONSHIP, required: false, options: [ diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php index 0712b9f2e5..88cb161505 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Create.php @@ -14,7 +14,6 @@ use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -78,7 +77,6 @@ class Create extends Action ->inject('queueForDatabase') ->inject('queueForEvents') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } @@ -95,8 +93,7 @@ class Create extends Action Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, - array $plan, - Authorization $authorization + array $plan ): void { if (!App::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() . '.'); @@ -135,8 +132,7 @@ class Create extends Action $response, $dbForProject, $queueForDatabase, - $queueForEvents, - $authorization + $queueForEvents ); $attribute->setAttribute('encrypt', $encrypt); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php index 096481198c..6687178cb1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/String/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -73,7 +72,6 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } @@ -87,8 +85,7 @@ class Update extends Action ?string $newKey, UtopiaResponse $response, Database $dbForProject, - Event $queueForEvents, - Authorization $authorization + Event $queueForEvents ): void { $attribute = $this->updateAttribute( databaseId: $databaseId, @@ -96,7 +93,6 @@ class Update extends Action key: $key, dbForProject: $dbForProject, queueForEvents: $queueForEvents, - authorization: $authorization, type: Database::VAR_STRING, size: $size, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php index 31b012754d..2d3b0c6168 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -71,7 +70,6 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } @@ -85,8 +83,7 @@ class Create extends Action UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, - Event $queueForEvents, - Authorization $authorization + Event $queueForEvents ): void { $attribute = $this->createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -96,7 +93,7 @@ class Create extends Action 'default' => $default, 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_URL, - ]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); + ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php index 46f2ec3acd..ebaea9e61d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/URL/Update.php @@ -11,7 +11,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -70,7 +69,6 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } @@ -83,8 +81,7 @@ class Update extends Action ?string $newKey, UtopiaResponse $response, Database $dbForProject, - Event $queueForEvents, - Authorization $authorization + Event $queueForEvents ): void { $attribute = $this->updateAttribute( $databaseId, @@ -92,7 +89,6 @@ class Update extends Action $key, $dbForProject, $queueForEvents, - $authorization, type: Database::VAR_STRING, filter: APP_DATABASE_ATTRIBUTE_URL, default: $default, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php index be61b260b3..c2af3ac945 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php @@ -64,13 +64,12 @@ class XList extends Action ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php index 93812585ea..922cc45428 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Create.php @@ -78,13 +78,12 @@ class Create extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php index 67f53fa33a..d124a47289 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php @@ -64,13 +64,12 @@ class Delete extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index 14b09777a8..08eea88e19 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -258,9 +258,9 @@ abstract class Action extends DatabasesAction Document $collection, Document $document, Database $dbForProject, + /* options */ array &$collectionsCache, - Authorization $authorization, ?int &$operations = null, ): bool { @@ -297,7 +297,7 @@ abstract class Action extends DatabasesAction $relatedCollectionId = $relationship->getAttribute('relatedCollection'); if (!isset($collectionsCache[$relatedCollectionId])) { - $relatedCollectionDoc = $authorization->skip( + $relatedCollectionDoc = Authorization::skip( fn () => $dbForProject->getDocument( 'database_' . $database->getSequence(), $relatedCollectionId @@ -323,8 +323,7 @@ abstract class Action extends DatabasesAction document: $relation, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - operations: $operations, - authorization: $authorization + operations: $operations ); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php index 158a44c1b3..fb5925c291 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Decrement.php @@ -85,21 +85,20 @@ class Decrement extends Action ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan): void { - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception($this->getParentNotFoundException()); } @@ -107,7 +106,7 @@ class Decrement extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php index 9045954789..5172890046 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Attribute/Increment.php @@ -85,21 +85,20 @@ class Increment extends Action ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, array $plan): void { - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty()) { throw new Exception($this->getParentNotFoundException()); } @@ -107,7 +106,7 @@ class Increment extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index ec3db59668..1320a0c9bc 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -24,7 +24,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -133,10 +132,9 @@ class Create extends Action ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, Authorization $authorization): void + public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void { $data = \is_string($data) ? \json_decode($data, true) @@ -180,19 +178,19 @@ class Create extends Action $documents = [$data]; } - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($isBulk && !$isAPIKey && !$isPrivilegedUser) { throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE); } - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -206,7 +204,7 @@ class Create extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Bulk create is not supported for ' . $this->getSDKNamespace() .' with relationship ' . $this->getStructureContext()); } - $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $dbForProject, $authorization) { + $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk) { $allowedPermissions = [ Database::PERMISSION_READ, Database::PERMISSION_UPDATE, @@ -249,8 +247,8 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization->hasRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $authorization->getRoles()) . ')'); + if (!Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', Authorization::getRoles()) . ')'); } } } @@ -261,25 +259,21 @@ class Create extends Action $operations = 0; - $checkPermissions = function (Document $collection, Document $document, string $permission) use ($isAPIKey, $isPrivilegedUser, &$checkPermissions, $dbForProject, $database, &$operations, $authorization) { + $checkPermissions = function (Document $collection, Document $document, string $permission) use ($isAPIKey, $isPrivilegedUser, &$checkPermissions, $dbForProject, $database, &$operations) { $operations++; $documentSecurity = $collection->getAttribute('documentSecurity', false); + $validator = new Authorization($permission); - $validCollection = $authorization->isValid( - new Input($permission, $collection->getPermissionsByType($permission)) - ); - if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$validCollection) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + $valid = $validator->isValid($collection->getPermissionsByType($permission)); + if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$valid) { + throw new Exception(Exception::USER_UNAUTHORIZED); } if ($permission === Database::PERMISSION_UPDATE) { - $validDocument = $authorization->isValid( - new Input($permission, $document->getUpdate()) - ); - $valid = $validCollection || $validDocument; + $valid = $valid || $validator->isValid($document->getUpdate()); if ($documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + throw new Exception(Exception::USER_UNAUTHORIZED); } } @@ -304,7 +298,7 @@ class Create extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $authorization->skip( + $relatedCollection = Authorization::skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -320,7 +314,7 @@ class Create extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $current = $authorization->skip( + $current = Authorization::skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId()) ); @@ -375,7 +369,7 @@ class Create extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -474,7 +468,6 @@ class Create extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - authorization: $authorization ); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php index 93ad7dc2a8..194bf27816 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php @@ -83,7 +83,6 @@ class Delete extends Action ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } @@ -98,19 +97,18 @@ class Delete extends Action Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, - array $plan, - Authorization $authorization + array $plan ): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -123,7 +121,7 @@ class Delete extends Action // Use transaction-aware document retrieval to see changes from same transaction $document = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $document = $authorization->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $document = Authorization::skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($document->isEmpty()) { @@ -133,7 +131,7 @@ class Delete extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -207,7 +205,6 @@ class Delete extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - authorization: $authorization ); $queueForStatsUsage diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php index fa89d5fa32..c92a487697 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php @@ -70,21 +70,20 @@ class Get extends Action ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState): void { - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -126,7 +125,6 @@ class Get extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - authorization: $authorization, operations: $operations ); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php index 68fd41221d..241b0c4ede 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Logs/XList.php @@ -73,13 +73,12 @@ class XList extends Action ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index 0aca4a08c3..ecdbc738a1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -87,11 +87,10 @@ class Update extends Action ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan): void { $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array @@ -99,16 +98,16 @@ class Update extends Action throw new Exception($this->getMissingPayloadException()); } - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); @@ -126,7 +125,7 @@ class Update extends Action // Use transaction-aware document retrieval to see changes from same transaction $document = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $document = $authorization->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $document = Authorization::skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($document->isEmpty()) { @@ -141,7 +140,7 @@ class Update extends Action ]); // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -154,7 +153,7 @@ class Update extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization->hasRole($role)) { + if (!Authorization::isRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -172,7 +171,7 @@ class Update extends Action $operations = 0; - $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations, $authorization) { + $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations) { $operations++; $relationships = \array_filter( @@ -196,7 +195,7 @@ class Update extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $authorization->skip( + $relatedCollection = Authorization::skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -213,7 +212,7 @@ class Update extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $oldDocument = $authorization->skip(fn () => $dbForProject->getDocument( + $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId() )); @@ -250,7 +249,7 @@ class Update extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -341,7 +340,6 @@ class Update extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - authorization: $authorization, ); $response->dynamic($document, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 5ec455b947..7901865b62 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -91,11 +91,10 @@ class Upsert extends Action ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Document $user, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Document $user, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage, TransactionState $transactionState, array $plan): void { $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array @@ -107,15 +106,15 @@ class Upsert extends Action throw new Exception($this->getMissingPayloadException()); } - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -140,7 +139,7 @@ class Upsert extends Action // Use transaction-aware document retrieval to see changes from same transaction $oldDocument = $transactionState->getDocument($collectionTableId, $documentId, $transactionId); } else { - $oldDocument = $authorization->skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); + $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument($collectionTableId, $documentId)); } if ($oldDocument->isEmpty()) { if (!empty($user->getId())) { @@ -156,7 +155,7 @@ class Upsert extends Action } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { @@ -169,7 +168,7 @@ class Upsert extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization->hasRole($role)) { + if (!Authorization::isRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -182,7 +181,7 @@ class Upsert extends Action $newDocument = new Document($data); $operations = 0; - $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations, $authorization) { + $setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations) { $operations++; $relationships = \array_filter( @@ -206,7 +205,7 @@ class Upsert extends Action } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = $authorization->skip( + $relatedCollection = Authorization::skip( fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId) ); @@ -223,7 +222,7 @@ class Upsert extends Action if ($relation instanceof Document) { $relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser); - $oldDocument = $authorization->skip(fn () => $dbForProject->getDocument( + $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId() )); @@ -260,7 +259,7 @@ class Upsert extends Action // Handle transaction staging if ($transactionId !== null) { $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -362,7 +361,6 @@ class Upsert extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - authorization: $authorization ); $relationships = \array_map( diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index a5a3ac0eb4..630170a031 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -74,21 +74,20 @@ class XList extends Action ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, TransactionState $transactionState): void { - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception($this->getParentNotFoundException()); } @@ -116,7 +115,7 @@ class XList extends Action $documentId = $cursor->getValue(); - $cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId)); if ($cursorDocument->isEmpty()) { $type = ucfirst($this->getContext()); @@ -162,8 +161,7 @@ class XList extends Action document: $document, dbForProject: $dbForProject, collectionsCache: $collectionsCache, - authorization: $authorization, - operations: $operations + operations: $operations, ); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php index 725b53ff9e..89739570c7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Get.php @@ -57,13 +57,12 @@ class Get extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, UtopiaResponse $response, Database $dbForProject): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php index 6afc29a265..9fb438d577 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php @@ -79,13 +79,12 @@ class Create extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php index 89d79ef353..2bccfdfb52 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php @@ -70,13 +70,12 @@ class Delete extends Action ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void { - $db = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php index 27e0767f88..3d118d1922 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php @@ -59,13 +59,12 @@ class Get extends Action ->param('key', null, new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $key, UtopiaResponse $response, Database $dbForProject): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php index d6e59dc4fa..88b3a32e0b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php @@ -66,14 +66,13 @@ class XList extends Action ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject): void { /** @var Document $database */ - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -113,7 +112,7 @@ class XList extends Action } $indexId = $cursor->getValue(); - $cursorDocument = $authorization->skip(fn () => $dbForProject->find('indexes', [ + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionInternalId', [$collection->getSequence()]), Query::equal('databaseInternalId', [$database->getSequence()]), Query::equal('key', [$indexId]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php index f193c15299..b202120bad 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Logs/XList.php @@ -72,13 +72,12 @@ class XList extends Action ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -116,9 +115,9 @@ class XList extends Action $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) - $os = $detector->getOS() ?: []; - $client = $detector->getClient() ?: []; - $device = $detector->getDevice() ?: []; + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); $output[$i] = new Document([ 'event' => $log['event'], @@ -126,20 +125,20 @@ class XList extends Action 'userEmail' => $log['data']['userEmail'] ?? null, 'userName' => $log['data']['userName'] ?? null, 'mode' => $log['data']['mode'] ?? null, - 'ip' => $log['ip'] ?? null, - 'time' => $log['time'] ?? null, - 'osCode' => $os['osCode'] ?? null, - 'osName' => $os['osName'] ?? null, - 'osVersion' => $os['osVersion'] ?? null, - 'clientType' => $client['clientType'] ?? null, - 'clientCode' => $client['clientCode'] ?? null, - 'clientName' => $client['clientName'] ?? null, - 'clientVersion' => $client['clientVersion'] ?? null, - 'clientEngine' => $client['clientEngine'] ?? null, - 'clientEngineVersion' => $client['clientEngineVersion'] ?? null, - 'deviceName' => $device['deviceName'] ?? null, - 'deviceBrand' => $device['deviceBrand'] ?? null, - 'deviceModel' => $device['deviceModel'] ?? null + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] ]); $record = $geodb->get($log['ip']); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php index c26a68c068..7575c9803b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php @@ -71,13 +71,12 @@ class Update extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php index beca779bf6..9cf7b85267 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Usage/Get.php @@ -63,11 +63,10 @@ class Get extends Action ->param('collectionId', '', new UID(), 'Collection ID.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $range, string $collectionId, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $range, string $collectionId, UtopiaResponse $response, Database $dbForProject): void { $database = $dbForProject->getDocument('databases', $databaseId); $collectionDocument = $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId); @@ -84,7 +83,7 @@ class Get extends Action str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getSequence(), $collectionDocument->getSequence()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php index 11b60e35a7..286e48420a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php @@ -67,13 +67,12 @@ class XList extends Action ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, array $queries, string $search, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, array $queries, string $search, bool $includeTotal, UtopiaResponse $response, Database $dbForProject): void { - $database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php index 41d3f3022a..c4c5bf8b51 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Create.php @@ -55,11 +55,10 @@ class Create extends Action ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('authorization') ->callback($this->action(...)); } - public function action(int $ttl, UtopiaResponse $response, Database $dbForProject, Document $user, Authorization $authorization): void + public function action(int $ttl, UtopiaResponse $response, Database $dbForProject, Document $user): void { $permissions = []; if (!empty($user->getId())) { @@ -74,7 +73,7 @@ class Create extends Action } } - $transaction = $authorization->skip(fn () => $dbForProject->createDocument('transactions', new Document([ + $transaction = Authorization::skip(fn () => $dbForProject->createDocument('transactions', new Document([ '$id' => ID::unique(), '$permissions' => $permissions, 'status' => 'pending', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index 98a0708f66..bd94c1c7eb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -18,7 +18,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\ArrayList; @@ -64,22 +63,21 @@ class Create extends Action ->inject('dbForProject') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $transactionId, array $operations, UtopiaResponse $response, Database $dbForProject, TransactionState $transactionState, array $plan, Authorization $authorization): void + public function action(string $transactionId, array $operations, UtopiaResponse $response, Database $dbForProject, TransactionState $transactionState, array $plan): void { if (empty($operations)) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Operations array cannot be empty'); } - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); // API keys and admins can read any transaction, regular users need permissions $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -115,13 +113,13 @@ class Create extends Action throw new Exception(Exception::USER_UNAUTHORIZED); } - $database = $databases[$operation['databaseId']] ??= $authorization->skip(fn () => $dbForProject->getDocument('databases', $operation['databaseId'])); + $database = $databases[$operation['databaseId']] ??= Authorization::skip(fn () => $dbForProject->getDocument('databases', $operation['databaseId'])); if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = $collections[$operation[$this->getGroupId()]] ??= - $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $operation[$this->getGroupId()])); + Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $operation[$this->getGroupId()])); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -167,20 +165,14 @@ class Create extends Action // For individual operations, enforce permissions unless using API key/admin if (!$isAPIKey && !$isPrivilegedUser) { $documentSecurity = $collection->getAttribute('documentSecurity', false); - - $collectionValid = $authorization->isValid( - new Input($permissionType, $collection->getPermissionsByType($permissionType)) - ); + $validator = new Authorization($permissionType); + $collectionValid = $validator->isValid($collection->getPermissionsByType($permissionType)); $documentValid = false; if ($document !== null && !$document->isEmpty() && $documentSecurity) { if ($permissionType === Database::PERMISSION_UPDATE) { - $documentValid = $authorization->isValid( - new Input(Database::PERMISSION_UPDATE, $document->getUpdate()) - ); + $documentValid = $validator->isValid($document->getUpdate()); } elseif ($permissionType === Database::PERMISSION_DELETE) { - $documentValid = $authorization->isValid( - new Input(Database::PERMISSION_DELETE, $document->getDelete()) - ); + $documentValid = $validator->isValid($document->getDelete()); } } @@ -197,7 +189,7 @@ class Create extends Action // Users can only set permissions for roles they have if (isset($operation['data']['$permissions'])) { $permissions = $operation['data']['$permissions']; - $roles = $authorization->getRoles(); + $roles = Authorization::getRoles(); foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -209,7 +201,7 @@ class Create extends Action $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!$authorization->hasRole($role)) { + if (!Authorization::isRole($role)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } @@ -238,7 +230,7 @@ class Create extends Action } } - $transaction = $authorization->skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { + $transaction = Authorization::skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { $dbForProject->createDocuments('transactionLogs', $staged); return $dbForProject->increaseDocumentAttribute( 'transactions', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index ec5f0e4c04..899c2b3eaf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -76,7 +76,6 @@ class Update extends Action ->inject('queueForRealtime') ->inject('queueForFunctions') ->inject('queueForWebhooks') - ->inject('authorization') ->callback($this->action(...)); } @@ -103,7 +102,7 @@ class Update extends Action * @throws Structure * @throws \Utopia\Exception */ - public function action(string $transactionId, bool $commit, bool $rollback, UtopiaResponse $response, Database $dbForProject, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, Authorization $authorization): void + public function action(string $transactionId, bool $commit, bool $rollback, UtopiaResponse $response, Database $dbForProject, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks): void { if (!$commit && !$rollback) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Either commit or rollback must be true'); @@ -112,11 +111,11 @@ class Update extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Cannot commit and rollback at the same time'); } - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $transaction = ($isAPIKey || $isPrivilegedUser) - ? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) + ? Authorization::skip(fn () => $dbForProject->getDocument('transactions', $transactionId)) : $dbForProject->getDocument('transactions', $transactionId); if ($transaction->isEmpty()) { throw new Exception(Exception::TRANSACTION_NOT_FOUND); @@ -138,12 +137,12 @@ class Update extends Action $databaseOperations = []; try { - $dbForProject->withTransaction(function () use ($dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, $queueForEvents, $queueForStatsUsage, $queueForRealtime, $queueForFunctions, $queueForWebhooks, $authorization) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + $dbForProject->withTransaction(function () use ($dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, $queueForEvents, $queueForStatsUsage, $queueForRealtime, $queueForFunctions, $queueForWebhooks) { + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'committing', ]))); - $operations = $authorization->skip(fn () => $dbForProject->find('transactionLogs', [ + $operations = Authorization::skip(fn () => $dbForProject->find('transactionLogs', [ Query::equal('transactionInternalId', [$transaction->getSequence()]), Query::orderAsc(), Query::limit(PHP_INT_MAX), @@ -166,7 +165,7 @@ class Update extends Action } if (!isset($collections[$collectionId])) { - $collections[$collectionId] = $authorization->skip( + $collections[$collectionId] = Authorization::skip( fn () => $dbForProject->getCollection($collectionId) ); } @@ -231,7 +230,7 @@ class Update extends Action } } - $transaction = $authorization->skip(fn () => $dbForProject->updateDocument( + $transaction = Authorization::skip(fn () => $dbForProject->updateDocument( 'transactions', $transactionId, new Document(['status' => 'committed']) @@ -243,32 +242,32 @@ class Update extends Action }); } catch (NotFoundException $e) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::DOCUMENT_NOT_FOUND, previous: $e); } catch (DuplicateException|ConflictException $e) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::TRANSACTION_CONFLICT, previous: $e); } catch (StructureException $e) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage()); } catch (LimitException $e) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, $e->getMessage()); } catch (TransactionException $e) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::TRANSACTION_FAILED, $e->getMessage()); } catch (QueryException $e) { - $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ + Authorization::skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'failed', ]))); throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); @@ -296,11 +295,11 @@ class Update extends Action $data = $data->getArrayCopy(); } - $database = $authorization->skip(fn () => $dbForProject->findOne('databases', [ + $database = Authorization::skip(fn () => $dbForProject->findOne('databases', [ Query::equal('$sequence', [$databaseInternalId]) ])); - $collection = $authorization->skip(fn () => $dbForProject->findOne('database_' . $databaseInternalId, [ + $collection = Authorization::skip(fn () => $dbForProject->findOne('database_' . $databaseInternalId, [ Query::equal('$sequence', [$collectionInternalId]) ])); @@ -392,7 +391,7 @@ class Update extends Action } if ($rollback) { - $transaction = $authorization->skip(fn () => $dbForProject->updateDocument( + $transaction = Authorization::skip(fn () => $dbForProject->updateDocument( 'transactions', $transactionId, new Document(['status' => 'failed']) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php index 7668ad0a79..c9de9d5217 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/Get.php @@ -59,11 +59,10 @@ class Get extends Action ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $databaseId, string $range, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $range, UtopiaResponse $response, Database $dbForProject): void { $database = $dbForProject->getDocument('databases', $databaseId); @@ -82,7 +81,7 @@ class Get extends Action str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES) ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php index 757f845c68..c13149cfc7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Usage/XList.php @@ -56,11 +56,10 @@ class XList extends Action ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $range, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $range, UtopiaResponse $response, Database $dbForProject): void { $periods = Config::getParam('usage', []); @@ -75,7 +74,7 @@ class XList extends Action METRIC_DATABASES_OPERATIONS_WRITES, ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php index 44674b68ca..d9dfc15ca8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Create.php @@ -60,7 +60,6 @@ class Create extends BooleanCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php index b3643b0e18..3b83e71c12 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Boolean/Update.php @@ -61,7 +61,6 @@ class Update extends BooleanUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php index 5a5970c3bb..69d6bd2b4b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php @@ -62,7 +62,6 @@ class Create extends DatetimeCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php index 08bb04b4e5..255abf00bf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Update.php @@ -63,7 +63,6 @@ class Update extends DatetimeUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php index 62152453fe..26f4ffa898 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Delete.php @@ -58,7 +58,6 @@ class Delete extends AttributesDelete ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php index 050e031591..58ea459d0f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Create.php @@ -61,7 +61,6 @@ class Create extends EmailCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php index c58257c8e1..0105345555 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Email/Update.php @@ -62,7 +62,6 @@ class Update extends EmailUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php index cc2c109f6a..8ab8019626 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Create.php @@ -64,7 +64,6 @@ class Create extends EnumCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php index bdb32de1ab..968c84c56b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Enum/Update.php @@ -65,7 +65,6 @@ class Update extends EnumUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php index acc82f406b..21e855d912 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Create.php @@ -63,7 +63,6 @@ class Create extends FloatCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php index f53cd711e0..6a479ea266 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Float/Update.php @@ -64,7 +64,6 @@ class Update extends FloatUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php index 0e7e079a02..c20ef58a39 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Get.php @@ -61,7 +61,6 @@ class Get extends AttributesGet ->param('key', '', new Key(), 'Column Key.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php index 804ebc6e14..08912ebb56 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Create.php @@ -61,7 +61,6 @@ class Create extends IPCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php index e600c0a349..9df9f573a2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/IP/Update.php @@ -62,7 +62,6 @@ class Update extends IPUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php index 1980234536..eb9230f48f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Create.php @@ -63,7 +63,6 @@ class Create extends IntegerCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php index cbf574010c..6c707f1655 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Integer/Update.php @@ -64,7 +64,6 @@ class Update extends IntegerUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php index 469fb6851f..4aa173707b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Create.php @@ -61,7 +61,6 @@ class Create extends LineCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php index b6a1336c00..fd7d200eb3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Line/Update.php @@ -63,7 +63,6 @@ class Update extends LineUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php index 715348e1f4..b8ae563def 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Create.php @@ -61,7 +61,6 @@ class Create extends PointCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php index c0c4c10689..8b8dd7b66c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Point/Update.php @@ -63,7 +63,6 @@ class Update extends PointUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php index 38c9eaf284..e0a2cf32cd 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Create.php @@ -61,7 +61,6 @@ class Create extends PolygonCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php index 12d6b95a72..c49351fc59 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Polygon/Update.php @@ -63,7 +63,6 @@ class Update extends PolygonUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php index 84c2123f4d..cccc61beaa 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Create.php @@ -73,7 +73,6 @@ class Create extends RelationshipCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php index b87fc3d33a..5953d600f8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Relationship/Update.php @@ -65,7 +65,6 @@ class Update extends RelationshipUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php index 02a04a2da0..8d37c9011b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Create.php @@ -66,7 +66,6 @@ class Create extends StringCreate ->inject('queueForDatabase') ->inject('queueForEvents') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php index 9270d7d7c7..43083616ba 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/String/Update.php @@ -65,7 +65,6 @@ class Update extends StringUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php index 051e8cbbbb..3fd6f1e463 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Create.php @@ -61,7 +61,6 @@ class Create extends URLCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php index 8854e701ef..64dfdfbf69 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/URL/Update.php @@ -62,7 +62,6 @@ class Update extends URLUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php index 950d38f8a7..1e0b641b32 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php @@ -52,7 +52,6 @@ class XList extends AttributesXList ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php index 5b598b1a12..68d3e772ec 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Create.php @@ -63,7 +63,6 @@ class Create extends CollectionCreate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php index 79b9e7beef..de068d5b29 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Delete.php @@ -55,7 +55,6 @@ class Delete extends CollectionDelete ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php index e264ec0411..be6ec5d9e7 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Get.php @@ -50,7 +50,6 @@ class Get extends CollectionGet ->param('tableId', '', new UID(), 'Table ID.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php index 165f014320..3802ee32b8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Create.php @@ -2,8 +2,6 @@ namespace Appwrite\Platform\Modules\Databases\Http\TablesDB\Tables\Indexes; -use Appwrite\Event\Database as EventDatabase; -use Appwrite\Event\Event; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Indexes\Create as IndexCreate; use Appwrite\SDK\AuthType; use Appwrite\SDK\ContentType; @@ -11,7 +9,6 @@ use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response as UtopiaResponse; use Utopia\Database\Database; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; @@ -69,15 +66,6 @@ class Create extends IndexCreate ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - - public function action(string $databaseId, string $tableId, string $key, string $type, array $columns, array $orders, array $lengths, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void - { - // Map TablesDB parameters to Collections API parameters - // tableId -> collectionId - // columns -> attributes - parent::action($databaseId, $tableId, $key, $type, $columns, $orders, $lengths, $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization); - } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php index cb552a086c..57ab466ee8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Delete.php @@ -61,7 +61,6 @@ class Delete extends IndexDelete ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php index 3c01f1b64d..271d842631 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/Get.php @@ -52,7 +52,6 @@ class Get extends IndexGet ->param('key', null, new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php index a6206f06dd..0ea52eaf1b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php @@ -54,7 +54,6 @@ class XList extends IndexXList ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php index f9111287c3..0680649544 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Logs/XList.php @@ -50,7 +50,6 @@ class XList extends CollectionLogXList ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php index b9896d282d..accb0392fe 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Delete.php @@ -66,7 +66,6 @@ class Delete extends DocumentsDelete ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php index e3bf1f9eef..856f17ed10 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Update.php @@ -68,7 +68,6 @@ class Update extends DocumentsUpdate ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php index 69a687d92f..492af25e9f 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Bulk/Upsert.php @@ -68,7 +68,6 @@ class Upsert extends DocumentsUpsert ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php index a660b008e1..42f2919ce1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Decrement.php @@ -67,7 +67,6 @@ class Decrement extends DecrementDocumentAttribute ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php index c2b69429ce..3d04d71c26 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Column/Increment.php @@ -67,7 +67,6 @@ class Increment extends IncrementDocumentAttribute ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php index 4fe7c2f9f6..d657e5596b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Create.php @@ -111,7 +111,6 @@ class Create extends DocumentCreate ->inject('queueForFunctions') ->inject('queueForWebhooks') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php index d76a907186..4c8b599c8c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Delete.php @@ -70,7 +70,6 @@ class Delete extends DocumentDelete ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php index ebc751a8e6..f355ebb9e6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Get.php @@ -58,7 +58,6 @@ class Get extends DocumentGet ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php index 5117e77ea9..5f1efa2953 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Logs/XList.php @@ -51,7 +51,6 @@ class XList extends DocumentLogXList ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php index 6265451b57..8f3786b8cf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php @@ -69,7 +69,6 @@ class Update extends DocumentUpdate ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php index 105750ddbd..d4cd61cfdd 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php @@ -72,7 +72,6 @@ class Upsert extends DocumentUpsert ->inject('queueForStatsUsage') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php index 9486a8abeb..cd6141a6b4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php @@ -59,7 +59,6 @@ class XList extends DocumentXList ->inject('dbForProject') ->inject('queueForStatsUsage') ->inject('transactionState') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php index aea590168d..a4bfb5bf23 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Update.php @@ -62,7 +62,6 @@ class Update extends CollectionUpdate ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php index b8be7edd56..0fb44ee94a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Usage/Get.php @@ -52,7 +52,6 @@ class Get extends CollectionUsageGet ->param('tableId', '', new UID(), 'Table ID.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php index eafb291037..5e8fcfc3c8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php @@ -55,7 +55,6 @@ class XList extends CollectionXList ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php index 1c6f0f95ca..bc79b86ca3 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Create.php @@ -50,7 +50,6 @@ class Create extends TransactionsCreate ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php index 2e3b73e395..5a98f22f37 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Operations/Create.php @@ -54,7 +54,6 @@ class Create extends OperationsCreate ->inject('dbForProject') ->inject('transactionState') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php index 250c9e0bc4..4d55af93a4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Transactions/Update.php @@ -60,7 +60,6 @@ class Update extends TransactionsUpdate ->inject('queueForRealtime') ->inject('queueForFunctions') ->inject('queueForWebhooks') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php index 87be8a9eab..89b9fbd8c2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/Get.php @@ -48,7 +48,6 @@ class Get extends DatabaseUsageGet ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php index 2cde337f5f..0bd96fc40a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Usage/XList.php @@ -46,7 +46,6 @@ class XList extends DatabaseUsageXList ->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index 593c3dde55..a699c0f097 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -27,7 +27,6 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; @@ -95,7 +94,6 @@ class Create extends Base ->inject('queueForFunctions') ->inject('geodb') ->inject('executor') - ->inject('authorization') ->callback($this->action(...)); } @@ -117,8 +115,7 @@ class Create extends Base StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, - Executor $executor, - Authorization $authorization + Executor $executor ) { $async = \strval($async) === 'true' || \strval($async) === '1'; @@ -156,10 +153,10 @@ class Create extends Base throw new Exception($validator->getDescription(), 400); } - $function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); @@ -175,7 +172,7 @@ class Create extends Base throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } - $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''))); + $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deploymentId', ''))); if ($deployment->getAttribute('resourceId') !== $function->getId()) { throw new Exception(Exception::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function'); @@ -189,8 +186,10 @@ class Create extends Base throw new Exception(Exception::BUILD_NOT_READY); } - if (!$authorization->isValid(new Input('execute', $function->getAttribute('execute')))) { // Check if user has write access to execute function - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + $validator = new Authorization('execute'); + + if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function + throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); } $jwt = ''; // initialize @@ -288,7 +287,7 @@ class Create extends Base if ($async) { if (is_null($scheduledAt)) { - $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); $queueForFunctions ->setType('http') ->setExecution($execution) @@ -329,7 +328,7 @@ class Create extends Base ->setAttribute('scheduleInternalId', $schedule->getSequence()) ->setAttribute('scheduledAt', $scheduledAt); - $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); } return $response @@ -482,7 +481,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))) ; - $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); } $executionResponse['headers']['x-appwrite-execution-id'] = $execution->getId(); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php index ccf345dbb5..666cb8310c 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Delete.php @@ -61,7 +61,6 @@ class Delete extends Base ->inject('dbForProject') ->inject('dbForPlatform') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } @@ -71,8 +70,7 @@ class Delete extends Base Response $response, Database $dbForProject, Database $dbForPlatform, - Event $queueForEvents, - Authorization $authorization + Event $queueForEvents ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -110,7 +108,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('active', false); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php index 69c4080f8a..42d78f8ca8 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Get.php @@ -52,7 +52,6 @@ class Get extends Base ->param('executionId', '', new UID(), 'Execution ID.') ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } @@ -60,13 +59,12 @@ class Get extends Base string $functionId, string $executionId, Response $response, - Database $dbForProject, - Authorization $authorization + Database $dbForProject ) { - $function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php index 52562aadf8..3d5ec06ace 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php @@ -60,7 +60,6 @@ class XList extends Base ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } @@ -69,13 +68,12 @@ class XList extends Base array $queries, bool $includeTotal, Response $response, - Database $dbForProject, - Authorization $authorization + Database $dbForProject ) { - $function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::FUNCTION_NOT_FOUND); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index 182f39e274..ec2a4baac5 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -115,7 +115,6 @@ class Create extends Base ->inject('dbForPlatform') ->inject('request') ->inject('gitHub') - ->inject('authorization') ->callback($this->action(...)); } @@ -153,8 +152,7 @@ class Create extends Base Func $queueForFunctions, Database $dbForPlatform, Request $request, - GitHub $github, - Authorization $authorization + GitHub $github ) { // Temporary abuse check @@ -239,7 +237,7 @@ class Create extends Base throw new Exception(Exception::FUNCTION_ALREADY_EXISTS); } - $schedule = $authorization->skip( + $schedule = Authorization::skip( fn () => $dbForPlatform->createDocument('schedules', new Document([ 'region' => $project->getAttribute('region'), 'resourceType' => SCHEDULE_RESOURCE_TYPE_FUNCTION, @@ -367,7 +365,7 @@ class Create extends Base // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $rule = $authorization->skip( + $rule = Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php index 6c9c9c3c6f..72d5589252 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Delete.php @@ -61,7 +61,6 @@ class Delete extends Base ->inject('queueForDeletes') ->inject('queueForEvents') ->inject('dbForPlatform') - ->inject('authorization') ->callback($this->action(...)); } @@ -71,8 +70,7 @@ class Delete extends Base Database $dbForProject, DeleteEvent $queueForDeletes, Event $queueForEvents, - Database $dbForPlatform, - Authorization $authorization + Database $dbForPlatform ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -89,7 +87,7 @@ class Delete extends Base $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('active', false); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queueForDeletes ->setType(DELETE_TYPE_DOCUMENT) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index b913848a13..8846329d27 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -62,7 +62,6 @@ class Update extends Base ->inject('dbForProject') ->inject('queueForEvents') ->inject('dbForPlatform') - ->inject('authorization') ->callback($this->action(...)); } @@ -73,8 +72,7 @@ class Update extends Base Response $response, Database $dbForProject, Event $queueForEvents, - Database $dbForPlatform, - Authorization $authorization + Database $dbForPlatform ) { $function = $dbForProject->getDocument('functions', $functionId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -103,7 +101,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queries = [ Query::equal('trigger', ['manual']), @@ -114,12 +112,12 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - $authorization->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment, $authorization) { + Authorization::skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); - $authorization->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }, $queries)); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php index d182bb67ea..318c2a2032 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php @@ -104,7 +104,6 @@ class Update extends Base ->inject('dbForPlatform') ->inject('gitHub') ->inject('executor') - ->inject('authorization') ->callback($this->action(...)); } @@ -135,8 +134,7 @@ class Update extends Base Build $queueForBuilds, Database $dbForPlatform, GitHub $github, - Executor $executor, - Authorization $authorization + Executor $executor ) { // TODO: If only branch changes, re-deploy $function = $dbForProject->getDocument('functions', $functionId); @@ -284,7 +282,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queueForEvents->setParam('functionId', $function->getId()); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php index 1fa65d0cc9..acb6995d6f 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/Get.php @@ -55,11 +55,10 @@ class Get extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $functionId, string $range, Response $response, Database $dbForProject, Authorization $authorization) + public function action(string $functionId, string $range, Response $response, Database $dbForProject) { $function = $dbForProject->getDocument('functions', $functionId); @@ -84,7 +83,7 @@ class Get extends Base str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_FAILED), ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php index 38a95d4469..6a4ded4db7 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Usage/XList.php @@ -52,11 +52,10 @@ class XList extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $range, Response $response, Database $dbForProject, Authorization $authorization) + public function action(string $range, Response $response, Database $dbForProject) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -76,7 +75,7 @@ class XList extends Base str_replace("{resourceType}", RESOURCE_TYPE_FUNCTIONS, METRIC_RESOURCE_TYPE_BUILDS_FAILED), ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php index ae74bfa98a..815d364dad 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Create.php @@ -65,7 +65,6 @@ class Create extends Base ->inject('dbForProject') ->inject('dbForPlatform') ->inject('project') - ->inject('authorization') ->callback($this->action(...)); } @@ -77,8 +76,7 @@ class Create extends Base Response $response, Database $dbForProject, Database $dbForPlatform, - Document $project, - Authorization $authorization + Document $project ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -121,7 +119,7 @@ class Create extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response ->setStatusCode(Response::STATUS_CODE_CREATED) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php index dcb80e4c8c..35f9618edb 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Delete.php @@ -57,7 +57,6 @@ class Delete extends Base ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') - ->inject('authorization') ->callback($this->action(...)); } @@ -66,8 +65,7 @@ class Delete extends Base string $variableId, Response $response, Database $dbForProject, - Database $dbForPlatform, - Authorization $authorization + Database $dbForPlatform ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -94,7 +92,7 @@ class Delete extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->noContent(); } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php index 959e2608d4..95fd235e4b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php @@ -62,7 +62,6 @@ class Update extends Base ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') - ->inject('authorization') ->callback($this->action(...)); } @@ -74,8 +73,7 @@ class Update extends Base ?bool $secret, Response $response, Database $dbForProject, - Database $dbForPlatform, - Authorization $authorization + Database $dbForPlatform ) { $function = $dbForProject->getDocument('functions', $functionId); @@ -112,7 +110,7 @@ class Update extends Base ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deploymentId'))); - $authorization->skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $response->dynamic($variable, Response::MODEL_VARIABLE); } diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 0a7a35d2e8..22b302f26e 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -27,6 +27,7 @@ use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Detector\Detection\Rendering\SSR; use Utopia\Detector\Detection\Rendering\XStatic; use Utopia\Detector\Detector\Rendering; @@ -924,11 +925,11 @@ class Builds extends Action ->trigger(); try { - $rule = $dbForPlatform->findOne('rules', [ + $rule = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal("projectInternalId", [$project->getSequence()]), Query::equal("type", ["deployment"]), Query::equal('deploymentInternalId', [$deployment->getSequence()]), - ]); + ])); if ($rule->isEmpty()) { throw new \Exception("Rule for build not found"); @@ -938,7 +939,7 @@ class Builds extends Action $client->setTimeout(\intval($resource->getAttribute('timeout', '15'))); $client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON); - $bucket = $dbForPlatform->getDocument('buckets', 'screenshots'); + $bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); $configs = [ 'screenshotLight' => [ @@ -1060,7 +1061,7 @@ class Builds extends Action 'metadata' => ['content_type' => $mimeType], ]); - $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file); + Authorization::skip(fn () => $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file)); $deployment->setAttribute($key, $fileId); } @@ -1283,7 +1284,7 @@ class Builds extends Action ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $resource->getAttribute('schedule')) ->setAttribute('active', !empty($resource->getAttribute('schedule')) && !empty($resource->getAttribute('deploymentId'))); - $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule); + Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); } Console::info('Deployment action finished'); @@ -1490,6 +1491,7 @@ class Builds extends Action * @return void * @throws Structure * @throws \Utopia\Database\Exception + * @throws Authorization * @throws Conflict * @throws Restricted */ @@ -1577,11 +1579,11 @@ class Builds extends Action default => throw new \Exception('Invalid resource type') }; - $rule = $dbForPlatform->findOne('rules', [ + $rule = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ Query::equal("projectInternalId", [$project->getSequence()]), Query::equal("type", ["deployment"]), Query::equal("deploymentInternalId", [$deployment->getSequence()]), - ]); + ])); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; $previewUrl = match($resource->getCollection()) { diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index 107c7b1389..aa622d8d84 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -87,7 +87,6 @@ class Create extends Action ->inject('deviceForLocal') ->inject('queueForBuilds') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } @@ -107,8 +106,7 @@ class Create extends Action Device $deviceForSites, Device $deviceForLocal, Build $queueForBuilds, - array $plan, - Authorization $authorization + array $plan ) { $activate = \strval($activate) === 'true' || \strval($activate) === '1'; @@ -277,7 +275,7 @@ class Create extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), @@ -342,7 +340,7 @@ class Create extends Action $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); $domain = ID::unique() . "." . $sitesDomain; $ruleId = md5($domain); - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php index 21f86aea35..065dd13e88 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php @@ -65,7 +65,6 @@ class Create extends Action ->inject('queueForEvents') ->inject('queueForBuilds') ->inject('deviceForSites') - ->inject('authorization') ->callback($this->action(...)); } @@ -79,8 +78,7 @@ class Create extends Action Database $dbForPlatform, Event $queueForEvents, Build $queueForBuilds, - Device $deviceForSites, - Authorization $authorization + Device $deviceForSites ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -148,7 +146,7 @@ class Create extends Action // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php index 4da3e9b34f..dc7d4c4ace 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -79,7 +79,6 @@ class Create extends Base ->inject('queueForEvents') ->inject('queueForBuilds') ->inject('gitHub') - ->inject('authorization') ->callback($this->action(...)); } @@ -98,8 +97,7 @@ class Create extends Base Document $project, Event $queueForEvents, Build $queueForBuilds, - GitHub $github, - Authorization $authorization + GitHub $github ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -132,7 +130,6 @@ class Create extends Base template: $template, github: $github, activate: $activate, - authorization: $authorization, ); $queueForEvents @@ -191,7 +188,7 @@ class Create extends Base // TODO: @christyjacob remove once we migrate the rules in 1.7.x $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); - $authorization->skip( + Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php index 09dc4a1618..ddad5d793a 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Vcs/Create.php @@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -73,7 +72,6 @@ class Create extends Base ->inject('queueForEvents') ->inject('queueForBuilds') ->inject('gitHub') - ->inject('authorization') ->callback($this->action(...)); } @@ -89,8 +87,7 @@ class Create extends Base Document $project, Event $queueForEvents, Build $queueForBuilds, - GitHub $github, - Authorization $authorization + GitHub $github ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -113,7 +110,6 @@ class Create extends Base template: $template, github: $github, activate: $activate, - authorization: $authorization, reference: $reference, referenceType: $type ); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index e3cab865a9..bb6bd4f632 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -60,7 +60,6 @@ class Update extends Base ->inject('dbForProject') ->inject('queueForEvents') ->inject('dbForPlatform') - ->inject('authorization') ->callback($this->action(...)); } @@ -71,8 +70,7 @@ class Update extends Base Response $response, Database $dbForProject, Event $queueForEvents, - Database $dbForPlatform, - Authorization $authorization + Database $dbForPlatform ) { $site = $dbForProject->getDocument('sites', $siteId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -106,12 +104,12 @@ class Update extends Base Query::equal('projectInternalId', [$project->getSequence()]) ]; - $authorization->skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment, $authorization) { + Authorization::skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getSequence()); - $authorization->skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }, $queries)); $queueForEvents diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php index 5c274d6a20..af96c10457 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/Get.php @@ -55,7 +55,6 @@ class Get extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } @@ -63,8 +62,7 @@ class Get extends Base string $siteId, string $range, Response $response, - Database $dbForProject, - Authorization $authorization + Database $dbForProject ) { $site = $dbForProject->getDocument('sites', $siteId); @@ -93,7 +91,7 @@ class Get extends Base ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php index a90cb0cab9..d36cc56ae5 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Usage/XList.php @@ -52,11 +52,10 @@ class XList extends Base ->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $range, Response $response, Database $dbForProject, Authorization $authorization) + public function action(string $range, Response $response, Database $dbForProject) { $periods = Config::getParam('usage', []); $stats = $usage = []; @@ -79,7 +78,7 @@ class XList extends Base METRIC_SITES_OUTBOUND, ]; - $authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) { + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { foreach ($metrics as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php index e05418b90d..5708f1b83b 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Action.php @@ -6,31 +6,32 @@ use Appwrite\Auth\Auth; use Appwrite\Extend\Exception; use Utopia\Database\Database; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Platform\Action as UtopiaAction; class Action extends UtopiaAction { - protected function getFileAndBucket(Database $dbForProject, Authorization $authorization, string $bucketId, string $fileId): array + protected function getFileAndBucket(Database $dbForProject, string $bucketId, string $fileId): array { - $bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - $isAPIKey = Auth::isAppUser($authorization->getRoles()); - $isPrivilegedUser = Auth::isPrivilegedUser($authorization->getRoles()); + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()))) { - throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription()); + $validator = new Authorization(Database::PERMISSION_READ); + $valid = $validator->isValid($bucket->getRead()); + if (!$valid) { + throw new Exception(Exception::USER_UNAUTHORIZED); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); if ($fileSecurity) { $file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId); } else { - $file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); } if ($file->isEmpty()) { diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php index 4760fef97f..e4de4c1380 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php @@ -14,7 +14,6 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Authorization\Input; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; @@ -66,23 +65,23 @@ class Create extends Action ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void + public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents): void { /** * @var Document $bucket * @var Document $file */ - ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $bucketId, $fileId); + ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId); $fileSecurity = $bucket->getAttribute('fileSecurity', false); - $bucketPermission = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate())); + $validator = new Authorization(Database::PERMISSION_UPDATE); + $bucketPermission = $validator->isValid($bucket->getUpdate()); if ($fileSecurity) { - $filePermission = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $file->getUpdate())); + $filePermission = $validator->isValid($file->getUpdate()); if (!$bucketPermission && !$filePermission) { throw new Exception(Exception::USER_UNAUTHORIZED); } diff --git a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php index 13da92cbc6..8a9301713b 100644 --- a/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php +++ b/src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php @@ -13,7 +13,6 @@ use Exception; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Scope\HTTP; use Utopia\Validator\Boolean; @@ -58,13 +57,12 @@ class XList extends Action ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) ->inject('response') ->inject('dbForProject') - ->inject('authorization') ->callback($this->action(...)); } - public function action(string $bucketId, string $fileId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Authorization $authorization) + public function action(string $bucketId, string $fileId, array $queries, bool $includeTotal, Response $response, Database $dbForProject) { - ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $bucketId, $fileId); + ['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId); $queries = Query::parseQueries($queries); $queries[] = Query::equal('resourceType', [TOKENS_RESOURCE_TYPE_FILES]); diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index cc6981fa1b..3e35c1c1fa 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -31,7 +31,6 @@ class Migrate extends Action ->inject('dbForPlatform') ->inject('getProjectDB') ->inject('register') - ->inject('authorisation') ->callback($this->action(...)); } @@ -48,8 +47,8 @@ class Migrate extends Action Database $dbForPlatform, callable $getProjectDB, Registry $register, - Authorization $authorization ): void { + Authorization::disable(); if (!\array_key_exists($version, Migration::$versions)) { Console::error("No migration found for version $version."); @@ -67,14 +66,14 @@ class Migrate extends Action $count = 0; $total = $dbForPlatform->count('projects') + 1; - $dbForPlatform->foreach('projects', function (Document $project) use ($dbForPlatform, $getProjectDB, $register, $migration, &$count, $total, $authorization) { + $dbForPlatform->foreach('projects', function (Document $project) use ($dbForPlatform, $getProjectDB, $register, $migration, &$count, $total) { /** @var Database $dbForProject */ $dbForProject = $getProjectDB($project); $dbForProject->disableValidation(); try { $migration - ->setProject($project, $dbForProject, $dbForPlatform, $authorization, $getProjectDB) + ->setProject($project, $dbForProject, $dbForPlatform, $getProjectDB) ->setPDO($register->get('db', true)) ->execute(); } catch (\Throwable $th) { @@ -89,7 +88,7 @@ class Migrate extends Action try { $migration - ->setProject($console, $getProjectDB($console), $dbForPlatform, $authorization, $getProjectDB) + ->setProject($console, $getProjectDB($console), $dbForPlatform, $getProjectDB) ->setPDO($register->get('db', true)) ->execute(); } catch (\Throwable $th) { diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 33a01346a8..e9a0e1d333 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -9,6 +9,7 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Queue\Broker\Pool as BrokerPool; use Utopia\System\System; @@ -61,7 +62,7 @@ abstract class ScheduleBase extends Action $accessedAt = $project->getAttribute('accessedAt', 0); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { $project->setAttribute('accessedAt', DateTime::now()); - $dbForPlatform->updateDocument('projects', $project->getId(), $project); + Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project)); } } } diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index 87d4858351..b64dd61f86 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -8,6 +8,7 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\System\System; /** @@ -44,7 +45,6 @@ class StatsResources extends Action ->inject('dbForPlatform') ->inject('logError') ->inject('queueForStatsResources') - ->inject('authorization') ->callback($this->action(...)); } @@ -61,7 +61,9 @@ class StatsResources extends Action $interval = (int) System::getEnv('_APP_STATS_RESOURCES_INTERVAL', '3600'); - Console::loop(function () use ($queue, $dbForPlatform) { + Console::loop(function () use ($queue) { + Authorization::disable(); + Authorization::setDefaultStatus(false); $last24Hours = (new \DateTime())->sub(\DateInterval::createFromDateString('24 hours')); /** diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 808adabb24..7df2770ac6 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -19,10 +19,12 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception as DatabaseException; +use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization as ValidatorAuthorization; use Utopia\DSN\DSN; use Utopia\Logger\Log; use Utopia\Platform\Action; @@ -199,6 +201,7 @@ class Deletes extends Action * @param string $datetime * @param Document|null $document * @return void + * @throws Authorization * @throws Conflict * @throws Restricted * @throws Structure @@ -989,14 +992,14 @@ class Deletes extends Action } Console::info("Deleting screenshots for deployment " . $deployment->getId()); - $bucket = $dbForPlatform->getDocument('buckets', 'screenshots'); + $bucket = ValidatorAuthorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); if ($bucket->isEmpty()) { Console::error('Failed to get bucket for deployment screenshots'); return; } foreach ($screenshotIds as $id) { - $file = $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $id); + $file = ValidatorAuthorization::skip(fn () => $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $id)); if ($file->isEmpty()) { Console::error('Failed to get deployment screenshot: ' . $id); diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index 8ed95ac2fc..df1833ad33 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -15,6 +15,7 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; @@ -325,6 +326,7 @@ class Functions extends Action * @param string|null $eventData * @param string|null $executionId * @return void + * @throws Authorization * @throws Structure * @throws \Utopia\Database\Exception * @throws Conflict diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 08782fd825..0bd5c50e04 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -84,7 +84,6 @@ class Migrations extends Action ->inject('deviceForFiles') ->inject('queueForMails') ->inject('plan') - ->inject('authorization') ->callback($this->action(...)); } @@ -102,7 +101,6 @@ class Migrations extends Action Device $deviceForFiles, Mail $queueForMails, array $plan, - Authorization $authorization, ): void { $payload = $message->getPayload() ?? []; $this->deviceForMigrations = $deviceForMigrations; @@ -129,7 +127,7 @@ class Migrations extends Action return; } - $this->processMigration($migration, $queueForRealtime, $queueForMails, $authorization); + $this->processMigration($migration, $queueForRealtime, $queueForMails); } /** @@ -298,7 +296,6 @@ class Migrations extends Action Document $migration, Realtime $queueForRealtime, Mail $queueForMails, - Authorization $authorization, ): void { $project = $this->dbForPlatform->getDocument('projects', $this->project->getId()); $tempAPIKey = $this->generateAPIKey($project); @@ -414,7 +411,7 @@ class Migrations extends Action $source?->success(); if ($migration->getAttribute('destination') === DestinationCSV::getName()) { - $this->handleCSVExportComplete($project, $migration, $queueForMails, $authorization); + $this->handleCSVExportComplete($project, $migration, $queueForMails); } } } @@ -435,8 +432,7 @@ class Migrations extends Action protected function handleCSVExportComplete( Document $project, Document $migration, - Mail $queueForMails, - Authorization $authorization, + Mail $queueForMails ): void { $options = $migration->getAttribute('options', []); $bucketId = 'default'; // Always use platform default bucket @@ -450,7 +446,7 @@ class Migrations extends Action throw new \Exception('User ' . $userInternalId . ' not found'); } - $bucket = $authorization->skip(fn () => $this->dbForPlatform->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $this->dbForPlatform->getDocument('buckets', $bucketId)); if ($bucket->isEmpty()) { throw new \Exception('Bucket not found'); } diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 76d87e2012..558f0cdf09 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -210,7 +210,7 @@ class Request extends UtopiaRequest { $forwardedUserAgent = $this->getHeader('x-forwarded-user-agent'); if (!empty($forwardedUserAgent)) { - $roles = $this->authorization->getRoles() ?? []; + $roles = Authorization::getRoles(); $isAppUser = Auth::isAppUser($roles); if ($isAppUser) { @@ -233,11 +233,4 @@ class Request extends UtopiaRequest ksort($params); return md5($this->getURI() . '*' . serialize($params) . '*' . APP_CACHE_BUSTER); } - - private ?Authorization $authorization = null; - - public function setAuthorization(Authorization $authorization): void - { - $this->authorization = $authorization; - } } diff --git a/src/Appwrite/Utopia/Request/Filter.php b/src/Appwrite/Utopia/Request/Filter.php index 6d47d4d150..56fed746d9 100644 --- a/src/Appwrite/Utopia/Request/Filter.php +++ b/src/Appwrite/Utopia/Request/Filter.php @@ -10,7 +10,7 @@ abstract class Filter private array $params; private ?Database $dbForProject; - public function __construct(?Database $dbForProject = null, array $params = []) + public function __construct(Database $dbForProject = null, array $params = []) { $this->params = $params; $this->dbForProject = $dbForProject; diff --git a/src/Appwrite/Utopia/Request/Filters/V20.php b/src/Appwrite/Utopia/Request/Filters/V20.php index e130178083..69e7da6b7a 100644 --- a/src/Appwrite/Utopia/Request/Filters/V20.php +++ b/src/Appwrite/Utopia/Request/Filters/V20.php @@ -7,6 +7,7 @@ use Appwrite\Utopia\Request\Filter; use Utopia\Database\Database; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; class V20 extends Filter { @@ -137,7 +138,7 @@ class V20 extends Filter } try { - $database = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument( + $database = Authorization::skip(fn () => $dbForProject->getDocument( 'databases', $databaseId )); @@ -149,10 +150,10 @@ class V20 extends Filter } try { - $collection = $dbForProject->getDocument( + $collection = Authorization::skip(fn () => $dbForProject->getDocument( 'database_' . $database->getSequence(), $collectionId - ); + )); if ($collection->isEmpty()) { return []; } diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 962ac37aa9..19a451e2c0 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -812,7 +812,7 @@ class Response extends SwooleResponse } if ($rule['sensitive']) { - $roles = $this->authorization->getRoles() ?? []; + $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); @@ -980,11 +980,4 @@ class Response extends SwooleResponse self::$showSensitive = false; } } - - private ?Authorization $authorization = null; - - public function setAuthorization(Authorization $authorization): void - { - $this->authorization = $authorization; - } } diff --git a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php index 0c9854160e..6496aa285a 100644 --- a/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/Legacy/Permissions/DatabasesPermissionsGuestTest.php @@ -17,19 +17,6 @@ class DatabasesPermissionsGuestTest extends Scope use SideClient; use DatabasesPermissionsScope; - private $authorization; - - public function getAuthorization(): Authorization - { - if (isset($this->authorization)) { - return $this->authorization; - } - - $this->authorization = new Authorization(); - - return $this->authorization; - } - public function createCollection(): array { $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ @@ -124,8 +111,8 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(201, $publicResponse['headers']['status-code']); $this->assertEquals(201, $privateResponse['headers']['status-code']); - $roles = $this->getAuthorization()->getRoles(); - $this->getAuthorization()->cleanRoles(); + $roles = Authorization::getRoles(); + Authorization::cleanRoles(); $publicDocuments = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ 'content-type' => 'application/json', @@ -147,7 +134,7 @@ class DatabasesPermissionsGuestTest extends Scope } foreach ($roles as $role) { - $this->getAuthorization()->addRole($role); + Authorization::setRole($role); } } @@ -158,8 +145,8 @@ class DatabasesPermissionsGuestTest extends Scope $privateCollectionId = $data['privateCollectionId']; $databaseId = $data['databaseId']; - $roles = $this->getAuthorization()->getRoles(); - $this->getAuthorization()->cleanRoles(); + $roles = Authorization::getRoles(); + Authorization::cleanRoles(); $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ 'content-type' => 'application/json', @@ -235,7 +222,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateDocument['headers']['status-code']); foreach ($roles as $role) { - $this->getAuthorization()->addRole($role); + Authorization::setRole($role); } } diff --git a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php index 84cb4bce3a..2f69c037d0 100644 --- a/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/TablesDB/Permissions/DatabasesPermissionsGuestTest.php @@ -17,19 +17,6 @@ class DatabasesPermissionsGuestTest extends Scope use SideClient; use DatabasesPermissionsScope; - private $authorization; - - public function getAuthorization(): Authorization - { - if (isset($this->authorization)) { - return $this->authorization; - } - - $this->authorization = new Authorization(); - return $this->authorization; - } - - public function createTable(): array { $database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([ @@ -124,8 +111,8 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(201, $publicResponse['headers']['status-code']); $this->assertEquals(201, $privateResponse['headers']['status-code']); - $roles = $this->getAuthorization()->getRoles(); - $this->getAuthorization()->cleanRoles(); + $roles = Authorization::getRoles(); + Authorization::cleanRoles(); $publicRows = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $publicTableId . '/rows', [ 'content-type' => 'application/json', @@ -147,7 +134,7 @@ class DatabasesPermissionsGuestTest extends Scope } foreach ($roles as $role) { - $this->getAuthorization()->addRole($role); + Authorization::setRole($role); } } @@ -158,8 +145,8 @@ class DatabasesPermissionsGuestTest extends Scope $privateTableId = $data['privateTableId']; $databaseId = $data['databaseId']; - $roles = $this->getAuthorization()->getRoles(); - $this->getAuthorization()->cleanRoles(); + $roles = Authorization::getRoles(); + Authorization::cleanRoles(); $publicResponse = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $publicTableId . '/rows', [ 'content-type' => 'application/json', @@ -235,7 +222,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateRow['headers']['status-code']); foreach ($roles as $role) { - $this->getAuthorization()->addRole($role); + Authorization::setRole($role); } } diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 63516f624d..4b7062dc22 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -40,6 +40,7 @@ class HealthCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('pass', $response['body']['statuses'][0]['status']); $this->assertIsInt($response['body']['statuses'][0]['ping']); diff --git a/tests/e2e/Services/Tokens/TokensBase.php b/tests/e2e/Services/Tokens/TokensBase.php index ca6feed5fa..a4461c06c2 100644 --- a/tests/e2e/Services/Tokens/TokensBase.php +++ b/tests/e2e/Services/Tokens/TokensBase.php @@ -94,7 +94,7 @@ trait TokensBase $this->assertEquals(401, $failedPreview['body']['code']); $this->assertEquals(401, $failedPreview['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedPreview['body']['type']); - $this->assertEquals('No permissions provided for action \'read\'', $failedPreview['body']['message']); + $this->assertEquals('The current user is not authorized to perform the requested action.', $failedPreview['body']['message']); // Extended file preview. Should fail as an anonymous user with no form of any access to the file. $failedCustomPreview = $this->client->call( @@ -113,7 +113,7 @@ trait TokensBase $this->assertEquals(401, $failedCustomPreview['body']['code']); $this->assertEquals(401, $failedCustomPreview['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedCustomPreview['body']['type']); - $this->assertEquals('No permissions provided for action \'read\'', $failedCustomPreview['body']['message']); + $this->assertEquals('The current user is not authorized to perform the requested action.', $failedCustomPreview['body']['message']); // File view. Should fail as an anonymous user with no form of any access to the file. $failedView = $this->client->call( @@ -124,7 +124,7 @@ trait TokensBase $this->assertEquals(401, $failedView['body']['code']); $this->assertEquals(401, $failedView['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedView['body']['type']); - $this->assertEquals('No permissions provided for action \'read\'', $failedView['body']['message']); + $this->assertEquals('The current user is not authorized to perform the requested action.', $failedView['body']['message']); // File download. Should fail as an anonymous user with no form of any access to the file. $failedDownload = $this->client->call( @@ -135,7 +135,7 @@ trait TokensBase $this->assertEquals(401, $failedDownload['body']['code']); $this->assertEquals(401, $failedDownload['headers']['status-code']); $this->assertEquals('user_unauthorized', $failedDownload['body']['type']); - $this->assertEquals('No permissions provided for action \'read\'', $failedDownload['body']['message']); + $this->assertEquals('The current user is not authorized to perform the requested action.', $failedDownload['body']['message']); return $data; } diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 5e883bf924..705da42879 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -13,27 +13,13 @@ use Utopia\Database\Validator\Roles; class AuthTest extends TestCase { - private $authorization; - - public function getAuthorization(): Authorization - { - if (isset($this->authorization)) { - return $this->authorization; - } - - $this->authorization = new Authorization(); - - return $this->authorization; - } - - /** * Reset Roles */ - public function setUp(): void + public function tearDown(): void { - $this->getAuthorization()->cleanRoles(); - $this->getAuthorization()->addRole(Role::any()->toString()); + Authorization::cleanRoles(); + Authorization::setRole(Role::any()->toString()); } public function testCookieName(): void @@ -361,7 +347,7 @@ class AuthTest extends TestCase '$id' => '' ]); - $roles = Auth::getRoles($user, new Authorization()); + $roles = Auth::getRoles($user); $this->assertCount(1, $roles); $this->assertContains(Role::guests()->toString(), $roles); } @@ -397,7 +383,7 @@ class AuthTest extends TestCase ] ]); - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $this->assertCount(13, $roles); $this->assertContains(Role::users()->toString(), $roles); @@ -418,21 +404,21 @@ class AuthTest extends TestCase $user['emailVerification'] = false; $user['phoneVerification'] = false; - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $this->assertContains(Role::users(Roles::DIMENSION_UNVERIFIED)->toString(), $roles); $this->assertContains(Role::user(ID::custom('123'), Roles::DIMENSION_UNVERIFIED)->toString(), $roles); // Enable single verification type $user['emailVerification'] = true; - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $this->assertContains(Role::users(Roles::DIMENSION_VERIFIED)->toString(), $roles); $this->assertContains(Role::user(ID::custom('123'), Roles::DIMENSION_VERIFIED)->toString(), $roles); } public function testPrivilegedUserRoles(): void { - $this->getAuthorization()->addRole(Auth::USER_ROLE_OWNER); + Authorization::setRole(Auth::USER_ROLE_OWNER); $user = new Document([ '$id' => ID::custom('123'), 'emailVerification' => true, @@ -458,7 +444,7 @@ class AuthTest extends TestCase ] ]); - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $this->assertCount(7, $roles); $this->assertNotContains(Role::users()->toString(), $roles); @@ -476,7 +462,7 @@ class AuthTest extends TestCase public function testAppUserRoles(): void { - $this->getAuthorization()->addRole(Auth::USER_ROLE_APPS); + Authorization::setRole(Auth::USER_ROLE_APPS); $user = new Document([ '$id' => ID::custom('123'), 'memberships' => [ @@ -500,7 +486,7 @@ class AuthTest extends TestCase ] ]); - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $this->assertCount(7, $roles); $this->assertNotContains(Role::users()->toString(), $roles); diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index 8fb7f3f666..8ba0374093 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -8,7 +8,6 @@ use PHPUnit\Framework\TestCase; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Authorization; class MessagingChannelsTest extends TestCase { @@ -35,19 +34,6 @@ class MessagingChannelsTest extends TestCase 'functions.1', ]; - - private $authorization; - - public function getAuthorization(): Authorization - { - if (isset($this->authorization)) { - return $this->authorization; - } - - $this->authorization = new Authorization(); - return $this->authorization; - } - public function setUp(): void { /** @@ -80,7 +66,7 @@ class MessagingChannelsTest extends TestCase ] ]); - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $parsedChannels = Realtime::convertChannels([0 => $channel], $user->getId()); @@ -104,7 +90,7 @@ class MessagingChannelsTest extends TestCase '$id' => '' ]); - $roles = Auth::getRoles($user, $this->getAuthorization()); + $roles = Auth::getRoles($user); $parsedChannels = Realtime::convertChannels([0 => $channel], $user->getId()); From 150d09f656534065b277916523fc2b9cf6f9c897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Wed, 19 Nov 2025 09:27:53 +0100 Subject: [PATCH 158/167] Update composer.lock --- composer.lock | 69 ++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/composer.lock b/composer.lock index 5856a5f2eb..d66945e3fc 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": "1042498bc589543427184b001fef3a1e", + "content-hash": "dc4eb1888275a24d596468924e272e25", "packages": [ { "name": "adhocore/jwt", @@ -3551,21 +3551,21 @@ }, { "name": "utopia-php/audit", - "version": "1.0.3", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "15656acfddb9d6f03c395b73673fc66c793c10a5" + "reference": "8c17065c2473d4ca799f65585ca74eb53e1be211" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/15656acfddb9d6f03c395b73673fc66c793c10a5", - "reference": "15656acfddb9d6f03c395b73673fc66c793c10a5", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/8c17065c2473d4ca799f65585ca74eb53e1be211", + "reference": "8c17065c2473d4ca799f65585ca74eb53e1be211", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "4.*" + "utopia-php/database": "*" }, "require-dev": { "laravel/pint": "1.*", @@ -3592,9 +3592,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/1.0.3" + "source": "https://github.com/utopia-php/audit/tree/1.0.2" }, - "time": "2025-11-04T11:27:42+00:00" + "time": "2025-10-20T07:14:26+00:00" }, { "name": "utopia-php/cache", @@ -3745,21 +3745,21 @@ }, { "name": "utopia-php/config", - "version": "dev-feat-config-adapters", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/utopia-php/config.git", - "reference": "02232da489a94576be0d8fb63c326003ccb6e337" + "reference": "6672bf6c1b54ba608593570cbef31bef75f17dd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/config/zipball/02232da489a94576be0d8fb63c326003ccb6e337", - "reference": "02232da489a94576be0d8fb63c326003ccb6e337", + "url": "https://api.github.com/repos/utopia-php/config/zipball/6672bf6c1b54ba608593570cbef31bef75f17dd8", + "reference": "6672bf6c1b54ba608593570cbef31bef75f17dd8", "shasum": "" }, "require": { "ext-yaml": "*", - "php": ">=8.1" + "php": ">=8.0" }, "require-dev": { "laravel/pint": "1.2.*", @@ -3786,9 +3786,9 @@ ], "support": { "issues": "https://github.com/utopia-php/config/issues", - "source": "https://github.com/utopia-php/config/tree/feat-config-adapters" + "source": "https://github.com/utopia-php/config/tree/1.0.0" }, - "time": "2025-11-18T14:59:26+00:00" + "time": "2025-11-18T17:02:00+00:00" }, { "name": "utopia-php/console", @@ -3840,16 +3840,16 @@ }, { "name": "utopia-php/database", - "version": "4.3.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "fe7a1326ad623609e65587fe8c01a630a7075fee" + "reference": "5da71b65a6123ce2e78795522b05b7458aabfbd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/fe7a1326ad623609e65587fe8c01a630a7075fee", - "reference": "fe7a1326ad623609e65587fe8c01a630a7075fee", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5da71b65a6123ce2e78795522b05b7458aabfbd7", + "reference": "5da71b65a6123ce2e78795522b05b7458aabfbd7", "shasum": "" }, "require": { @@ -3892,9 +3892,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/4.3.0" + "source": "https://github.com/utopia-php/database/tree/3.5.0" }, - "time": "2025-11-14T03:43:10+00:00" + "time": "2025-11-18T08:11:01+00:00" }, { "name": "utopia-php/detector", @@ -4456,16 +4456,16 @@ }, { "name": "utopia-php/migration", - "version": "1.3.4", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "81e1be6ff3257d4768aa7483cf64628836244a09" + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/81e1be6ff3257d4768aa7483cf64628836244a09", - "reference": "81e1be6ff3257d4768aa7483cf64628836244a09", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/731b3a963c58c30e0b2368695d57a7e8fcb7455c", + "reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c", "shasum": "" }, "require": { @@ -4474,7 +4474,7 @@ "ext-openssl": "*", "php": ">=8.1", "utopia-php/console": "0.0.*", - "utopia-php/database": "4.*", + "utopia-php/database": "3.*", "utopia-php/dsn": "0.2.*", "utopia-php/storage": "0.18.*" }, @@ -4505,9 +4505,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.3.4" + "source": "https://github.com/utopia-php/migration/tree/1.3.3" }, - "time": "2025-11-04T11:28:50+00:00" + "time": "2025-10-28T04:02:08+00:00" }, { "name": "utopia-php/mongo", @@ -8891,18 +8891,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/config", - "version": "dev-feat-config-adapters", - "alias": "1.0.0", - "alias_normalized": "1.0.0.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/config": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 61f8c99da7579897bb3da20cc04451ff37f32df1 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Wed, 19 Nov 2025 14:11:40 +0530 Subject: [PATCH 159/167] chore: release flutter 20.3.2 --- app/config/platforms.php | 2 +- docker-compose.override.yml | 7 ------- docs/sdks/flutter/CHANGELOG.md | 4 ++++ 3 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 docker-compose.override.yml diff --git a/app/config/platforms.php b/app/config/platforms.php index 2b5c107648..ce60b2f6c2 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -60,7 +60,7 @@ return [ [ 'key' => 'flutter', 'name' => 'Flutter', - 'version' => '20.3.1', + 'version' => '20.3.2', 'url' => 'https://github.com/appwrite/sdk-for-flutter', 'package' => 'https://pub.dev/packages/appwrite', 'enabled' => true, diff --git a/docker-compose.override.yml b/docker-compose.override.yml deleted file mode 100644 index 52c5058ab9..0000000000 --- a/docker-compose.override.yml +++ /dev/null @@ -1,7 +0,0 @@ -services: - appwrite: - # volumes: - # - ~/.ssh:/root/.ssh - environment: - - GH_TOKEN= - - GIT_EMAIL= diff --git a/docs/sdks/flutter/CHANGELOG.md b/docs/sdks/flutter/CHANGELOG.md index 2f26f34edd..40f703903f 100644 --- a/docs/sdks/flutter/CHANGELOG.md +++ b/docs/sdks/flutter/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 20.3.2 + +* Fix OAuth2 browser infinite redirect issue + ## 20.3.1 * Fix passing of `null` values and stripping only non-nullable optional parameters from the request body From 0974e1335f6b0f20102b7d1e4955196ba3ed3358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Wed, 19 Nov 2025 10:38:32 +0100 Subject: [PATCH 160/167] Cleanup --- app/init/configs.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/init/configs.php b/app/init/configs.php index 9519c757b3..9ecbe6114d 100644 --- a/app/init/configs.php +++ b/app/init/configs.php @@ -5,8 +5,6 @@ use Utopia\Config\Config; require_once __DIR__ . '/../config/storage/resource_limits.php'; -$configAdapter = new PHP(); - Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php', new PHP()); Config::load('events', __DIR__ . '/../config/events.php', new PHP()); Config::load('auth', __DIR__ . '/../config/auth.php', new PHP()); From bdbe94b56ffb4cc44ac31745da1e1da5e2382043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= <matejbaco2000@gmail.com> Date: Wed, 19 Nov 2025 11:02:29 +0100 Subject: [PATCH 161/167] Improce codeQL --- app/init/configs.php | 74 +++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/app/init/configs.php b/app/init/configs.php index 9ecbe6114d..51242af578 100644 --- a/app/init/configs.php +++ b/app/init/configs.php @@ -5,39 +5,41 @@ use Utopia\Config\Config; require_once __DIR__ . '/../config/storage/resource_limits.php'; -Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php', new PHP()); -Config::load('events', __DIR__ . '/../config/events.php', new PHP()); -Config::load('auth', __DIR__ . '/../config/auth.php', new PHP()); -Config::load('apis', __DIR__ . '/../config/apis.php', new PHP()); // List of APIs -Config::load('errors', __DIR__ . '/../config/errors.php', new PHP()); -Config::load('oAuthProviders', __DIR__ . '/../config/oAuthProviders.php', new PHP()); -Config::load('platforms', __DIR__ . '/../config/platforms.php', new PHP()); -Config::load('console', __DIR__ . '/../config/console.php', new PHP()); -Config::load('collections', __DIR__ . '/../config/collections.php', new PHP()); -Config::load('frameworks', __DIR__ . '/../config/frameworks.php', new PHP()); -Config::load('runtimes', __DIR__ . '/../config/runtimes.php', new PHP()); -Config::load('runtimes-v2', __DIR__ . '/../config/runtimes-v2.php', new PHP()); -Config::load('usage', __DIR__ . '/../config/usage.php', new PHP()); -Config::load('roles', __DIR__ . '/../config/roles.php', new PHP()); // User roles and scopes -Config::load('scopes', __DIR__ . '/../config/scopes.php', new PHP()); // User roles and scopes -Config::load('services', __DIR__ . '/../config/services.php', new PHP()); // List of services -Config::load('variables', __DIR__ . '/../config/variables.php', new PHP()); // List of env variables -Config::load('regions', __DIR__ . '/../config/regions.php', new PHP()); // List of available regions -Config::load('avatar-browsers', __DIR__ . '/../config/avatars/browsers.php', new PHP()); -Config::load('avatar-credit-cards', __DIR__ . '/../config/avatars/credit-cards.php', new PHP()); -Config::load('avatar-flags', __DIR__ . '/../config/avatars/flags.php', new PHP()); -Config::load('locale-codes', __DIR__ . '/../config/locale/codes.php', new PHP()); -Config::load('locale-currencies', __DIR__ . '/../config/locale/currencies.php', new PHP()); -Config::load('locale-eu', __DIR__ . '/../config/locale/eu.php', new PHP()); -Config::load('locale-languages', __DIR__ . '/../config/locale/languages.php', new PHP()); -Config::load('locale-phones', __DIR__ . '/../config/locale/phones.php', new PHP()); -Config::load('locale-countries', __DIR__ . '/../config/locale/countries.php', new PHP()); -Config::load('locale-continents', __DIR__ . '/../config/locale/continents.php', new PHP()); -Config::load('locale-templates', __DIR__ . '/../config/locale/templates.php', new PHP()); -Config::load('storage-logos', __DIR__ . '/../config/storage/logos.php', new PHP()); -Config::load('storage-mimes', __DIR__ . '/../config/storage/mimes.php', new PHP()); -Config::load('storage-inputs', __DIR__ . '/../config/storage/inputs.php', new PHP()); -Config::load('storage-outputs', __DIR__ . '/../config/storage/outputs.php', new PHP()); -Config::load('specifications', __DIR__ . '/../config/specifications.php', new PHP()); -Config::load('templates-function', __DIR__ . '/../config/templates/function.php', new PHP()); -Config::load('templates-site', __DIR__ . '/../config/templates/site.php', new PHP()); +$configAdapter = new PHP(); + +Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php', $configAdapter); +Config::load('events', __DIR__ . '/../config/events.php', $configAdapter); +Config::load('auth', __DIR__ . '/../config/auth.php', $configAdapter); +Config::load('apis', __DIR__ . '/../config/apis.php', $configAdapter); // List of APIs +Config::load('errors', __DIR__ . '/../config/errors.php', $configAdapter); +Config::load('oAuthProviders', __DIR__ . '/../config/oAuthProviders.php', $configAdapter); +Config::load('platforms', __DIR__ . '/../config/platforms.php', $configAdapter); +Config::load('console', __DIR__ . '/../config/console.php', $configAdapter); +Config::load('collections', __DIR__ . '/../config/collections.php', $configAdapter); +Config::load('frameworks', __DIR__ . '/../config/frameworks.php', $configAdapter); +Config::load('runtimes', __DIR__ . '/../config/runtimes.php', $configAdapter); +Config::load('runtimes-v2', __DIR__ . '/../config/runtimes-v2.php', $configAdapter); +Config::load('usage', __DIR__ . '/../config/usage.php', $configAdapter); +Config::load('roles', __DIR__ . '/../config/roles.php', $configAdapter); // User roles and scopes +Config::load('scopes', __DIR__ . '/../config/scopes.php', $configAdapter); // User roles and scopes +Config::load('services', __DIR__ . '/../config/services.php', $configAdapter); // List of services +Config::load('variables', __DIR__ . '/../config/variables.php', $configAdapter); // List of env variables +Config::load('regions', __DIR__ . '/../config/regions.php', $configAdapter); // List of available regions +Config::load('avatar-browsers', __DIR__ . '/../config/avatars/browsers.php', $configAdapter); +Config::load('avatar-credit-cards', __DIR__ . '/../config/avatars/credit-cards.php', $configAdapter); +Config::load('avatar-flags', __DIR__ . '/../config/avatars/flags.php', $configAdapter); +Config::load('locale-codes', __DIR__ . '/../config/locale/codes.php', $configAdapter); +Config::load('locale-currencies', __DIR__ . '/../config/locale/currencies.php', $configAdapter); +Config::load('locale-eu', __DIR__ . '/../config/locale/eu.php', $configAdapter); +Config::load('locale-languages', __DIR__ . '/../config/locale/languages.php', $configAdapter); +Config::load('locale-phones', __DIR__ . '/../config/locale/phones.php', $configAdapter); +Config::load('locale-countries', __DIR__ . '/../config/locale/countries.php', $configAdapter); +Config::load('locale-continents', __DIR__ . '/../config/locale/continents.php', $configAdapter); +Config::load('locale-templates', __DIR__ . '/../config/locale/templates.php', $configAdapter); +Config::load('storage-logos', __DIR__ . '/../config/storage/logos.php', $configAdapter); +Config::load('storage-mimes', __DIR__ . '/../config/storage/mimes.php', $configAdapter); +Config::load('storage-inputs', __DIR__ . '/../config/storage/inputs.php', $configAdapter); +Config::load('storage-outputs', __DIR__ . '/../config/storage/outputs.php', $configAdapter); +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); From 2443266ac5eceb8749b859c383ffb1bdf0999fd0 Mon Sep 17 00:00:00 2001 From: Jake Barnby <jakeb994@gmail.com> Date: Thu, 20 Nov 2025 17:10:47 +1300 Subject: [PATCH 162/167] Set downloadUrl on realtime event --- src/Appwrite/Platform/Workers/Migrations.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 0bd5c50e04..59cb3c5f16 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -411,7 +411,7 @@ class Migrations extends Action $source?->success(); if ($migration->getAttribute('destination') === DestinationCSV::getName()) { - $this->handleCSVExportComplete($project, $migration, $queueForMails); + $this->handleCSVExportComplete($project, $migration, $queueForMails, $queueForRealtime); } } } @@ -432,7 +432,8 @@ class Migrations extends Action protected function handleCSVExportComplete( Document $project, Document $migration, - Mail $queueForMails + Mail $queueForMails, + Realtime $queueForRealtime, ): void { $options = $migration->getAttribute('options', []); $bucketId = 'default'; // Always use platform default bucket @@ -530,6 +531,9 @@ class Migrations extends Action $endpoint = System::getEnv('_APP_DOMAIN', ''); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled' ? 'https' : 'http'; $downloadUrl = "{$protocol}://{$endpoint}/v1/storage/buckets/{$bucketId}/files/{$fileId}/push?project={$project->getId()}&jwt={$jwt}"; + $options['downloadUrl'] = $downloadUrl; + $migration->setAttribute('options', $options); + $this->updateMigrationDocument($migration, $project, $queueForRealtime); $this->sendCSVEmail( success: true, From fcce6f8d34378327d500c9273496b5536455fc78 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 20 Nov 2025 10:32:56 +0530 Subject: [PATCH 163/167] fix: override template deployment type enum name --- app/config/specs/open-api3-1.8.x-console.json | 2 +- app/config/specs/open-api3-1.8.x-server.json | 2 +- app/config/specs/open-api3-latest-console.json | 2 +- app/config/specs/open-api3-latest-server.json | 2 +- app/config/specs/swagger2-1.8.x-console.json | 2 +- app/config/specs/swagger2-1.8.x-server.json | 2 +- app/config/specs/swagger2-latest-console.json | 2 +- app/config/specs/swagger2-latest-server.json | 2 +- src/Appwrite/SDK/Specification/Format.php | 6 ++++++ 9 files changed, 14 insertions(+), 8 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 fded6c46b0..79ecfaf8ff 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -32337,7 +32337,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { 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 2cb6a74853..b83c1ca2c5 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -22861,7 +22861,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index fded6c46b0..79ecfaf8ff 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -32337,7 +32337,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 2cb6a74853..b83c1ca2c5 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -22861,7 +22861,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 28a4f76c61..55bdb0f091 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -32441,7 +32441,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index e760c1bb7d..eeee655d84 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -23014,7 +23014,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 28a4f76c61..55bdb0f091 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -32441,7 +32441,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index e760c1bb7d..eeee655d84 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -23014,7 +23014,7 @@ "commit", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/src/Appwrite/SDK/Specification/Format.php b/src/Appwrite/SDK/Specification/Format.php index c687df143a..c2e97f7f89 100644 --- a/src/Appwrite/SDK/Specification/Format.php +++ b/src/Appwrite/SDK/Specification/Format.php @@ -289,6 +289,12 @@ abstract class Format return 'VCSDeploymentType'; } break; + case 'createTemplateDeployment': + switch ($param) { + case 'type': + return 'TemplateDeploymentType'; + } + break; } break; case 'vcs': From 4b752c15e8743dddadc12ca59518e38560c3186e Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 20 Nov 2025 10:42:13 +0530 Subject: [PATCH 164/167] functions too --- app/config/specs/open-api3-1.8.x-console.json | 2 +- app/config/specs/open-api3-1.8.x-server.json | 2 +- app/config/specs/open-api3-latest-console.json | 2 +- app/config/specs/open-api3-latest-server.json | 2 +- app/config/specs/swagger2-1.8.x-console.json | 2 +- app/config/specs/swagger2-1.8.x-server.json | 2 +- app/config/specs/swagger2-latest-console.json | 2 +- app/config/specs/swagger2-latest-server.json | 2 +- src/Appwrite/SDK/Specification/Format.php | 6 ++++++ 9 files changed, 14 insertions(+), 8 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 79ecfaf8ff..e95f24ffcb 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -14424,7 +14424,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { 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 b83c1ca2c5..d9ebbda085 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -13213,7 +13213,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 79ecfaf8ff..e95f24ffcb 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -14424,7 +14424,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index b83c1ca2c5..d9ebbda085 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -13213,7 +13213,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 55bdb0f091..845f55d5fd 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -14366,7 +14366,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index eeee655d84..e58fa32c1f 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -13182,7 +13182,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 55bdb0f091..845f55d5fd 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -14366,7 +14366,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index eeee655d84..e58fa32c1f 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -13182,7 +13182,7 @@ "branch", "tag" ], - "x-enum-name": null, + "x-enum-name": "TemplateDeploymentType", "x-enum-keys": [] }, "reference": { diff --git a/src/Appwrite/SDK/Specification/Format.php b/src/Appwrite/SDK/Specification/Format.php index c2e97f7f89..11be265644 100644 --- a/src/Appwrite/SDK/Specification/Format.php +++ b/src/Appwrite/SDK/Specification/Format.php @@ -266,6 +266,12 @@ abstract class Format return 'VCSDeploymentType'; } break; + case 'createTemplateDeployment': + switch ($param) { + case 'type': + return 'TemplateDeploymentType'; + } + break; } break; case 'sites': From a2463f8cc34f3eb54fa01b8a6a9e7f5480d36687 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Thu, 20 Nov 2025 15:23:16 +0530 Subject: [PATCH 165/167] fix naming --- app/config/specs/open-api3-1.8.x-console.json | 4 ++-- app/config/specs/open-api3-1.8.x-server.json | 4 ++-- app/config/specs/open-api3-latest-console.json | 4 ++-- app/config/specs/open-api3-latest-server.json | 4 ++-- app/config/specs/swagger2-1.8.x-console.json | 4 ++-- app/config/specs/swagger2-1.8.x-server.json | 4 ++-- app/config/specs/swagger2-latest-console.json | 4 ++-- app/config/specs/swagger2-latest-server.json | 4 ++-- src/Appwrite/SDK/Specification/Format.php | 4 ++-- 9 files changed, 18 insertions(+), 18 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 e95f24ffcb..c56bb92c3a 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -14424,7 +14424,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -32337,7 +32337,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { 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 d9ebbda085..84af70dd5d 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -13213,7 +13213,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -22861,7 +22861,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index e95f24ffcb..c56bb92c3a 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -14424,7 +14424,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -32337,7 +32337,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index d9ebbda085..84af70dd5d 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -13213,7 +13213,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -22861,7 +22861,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 845f55d5fd..84b6060e1e 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -14366,7 +14366,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -32441,7 +32441,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index e58fa32c1f..b23d0d2fce 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -13182,7 +13182,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -23014,7 +23014,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 845f55d5fd..84b6060e1e 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -14366,7 +14366,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -32441,7 +32441,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index e58fa32c1f..b23d0d2fce 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -13182,7 +13182,7 @@ "branch", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { @@ -23014,7 +23014,7 @@ "commit", "tag" ], - "x-enum-name": "TemplateDeploymentType", + "x-enum-name": "TemplateReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/src/Appwrite/SDK/Specification/Format.php b/src/Appwrite/SDK/Specification/Format.php index 11be265644..ac318a39d4 100644 --- a/src/Appwrite/SDK/Specification/Format.php +++ b/src/Appwrite/SDK/Specification/Format.php @@ -269,7 +269,7 @@ abstract class Format case 'createTemplateDeployment': switch ($param) { case 'type': - return 'TemplateDeploymentType'; + return 'TemplateReferenceType'; } break; } @@ -298,7 +298,7 @@ abstract class Format case 'createTemplateDeployment': switch ($param) { case 'type': - return 'TemplateDeploymentType'; + return 'TemplateReferenceType'; } break; } From e2979410da0b19bdad1fafd71b5f65d5d5dcf2cf Mon Sep 17 00:00:00 2001 From: Steven Nguyen <1477010+stnguyen90@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:34:45 -0800 Subject: [PATCH 166/167] chore: update index descriptions to reflect table terminology Updated descriptions for indexes to refer to tables instead of collections. --- app/config/scopes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/scopes.php b/app/config/scopes.php index d90ca2eabf..a6ad98e4e0 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -47,10 +47,10 @@ return [ // List of publicly visible scopes 'description' => 'Access to create, update, and delete your project\'s database table\'s columns', ], 'indexes.read' => [ - 'description' => 'Access to read your project\'s database collection\'s indexes', + 'description' => 'Access to read your project\'s database table\'s indexes', ], 'indexes.write' => [ - 'description' => 'Access to create, update, and delete your project\'s database collection\'s indexes', + 'description' => 'Access to create, update, and delete your project\'s database table\'s indexes', ], 'documents.read' => [ 'description' => 'Access to read your project\'s database documents', From ba10bed27117a9718d0c5ef88d3714adf906f6d7 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal <chiragaggarwal5k@gmail.com> Date: Fri, 21 Nov 2025 09:56:26 +0530 Subject: [PATCH 167/167] chore: change VCSDeploymentType enum to VCSReferenceType --- app/config/specs/open-api3-1.8.x-console.json | 4 ++-- app/config/specs/open-api3-1.8.x-server.json | 4 ++-- app/config/specs/open-api3-latest-console.json | 4 ++-- app/config/specs/open-api3-latest-server.json | 4 ++-- app/config/specs/swagger2-1.8.x-console.json | 4 ++-- app/config/specs/swagger2-1.8.x-server.json | 4 ++-- app/config/specs/swagger2-latest-console.json | 4 ++-- app/config/specs/swagger2-latest-server.json | 4 ++-- src/Appwrite/SDK/Specification/Format.php | 4 ++-- 9 files changed, 18 insertions(+), 18 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 c56bb92c3a..365f926685 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -14524,7 +14524,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -32438,7 +32438,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { 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 84af70dd5d..a2a97c046e 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -13314,7 +13314,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -22963,7 +22963,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index c56bb92c3a..365f926685 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -14524,7 +14524,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -32438,7 +32438,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 84af70dd5d..a2a97c046e 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -13314,7 +13314,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -22963,7 +22963,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 84b6060e1e..5d2334764e 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -14467,7 +14467,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -32543,7 +32543,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index b23d0d2fce..b37aaac8e2 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -13284,7 +13284,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -23117,7 +23117,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 84b6060e1e..5d2334764e 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -14467,7 +14467,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -32543,7 +32543,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index b23d0d2fce..b37aaac8e2 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -13284,7 +13284,7 @@ "branch", "commit" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { @@ -23117,7 +23117,7 @@ "commit", "tag" ], - "x-enum-name": "VCSDeploymentType", + "x-enum-name": "VCSReferenceType", "x-enum-keys": [] }, "reference": { diff --git a/src/Appwrite/SDK/Specification/Format.php b/src/Appwrite/SDK/Specification/Format.php index ac318a39d4..b9e1c3b4ed 100644 --- a/src/Appwrite/SDK/Specification/Format.php +++ b/src/Appwrite/SDK/Specification/Format.php @@ -263,7 +263,7 @@ abstract class Format case 'createVcsDeployment': switch ($param) { case 'type': - return 'VCSDeploymentType'; + return 'VCSReferenceType'; } break; case 'createTemplateDeployment': @@ -292,7 +292,7 @@ abstract class Format case 'createVcsDeployment': switch ($param) { case 'type': - return 'VCSDeploymentType'; + return 'VCSReferenceType'; } break; case 'createTemplateDeployment':