diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 633bd46ea4..7c53b03b52 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -16,15 +16,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
- name: Build Appwrite
- uses: docker/build-push-action@v3
+ uses: docker/build-push-action@v6
with:
context: .
push: false
@@ -39,7 +39,7 @@ jobs:
VERSION=dev
- name: Cache Docker Image
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
@@ -51,10 +51,10 @@ jobs:
steps:
- name: checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Load Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
@@ -81,10 +81,10 @@ jobs:
needs: setup
steps:
- name: checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Load Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
@@ -113,6 +113,7 @@ jobs:
Console,
Databases,
Functions,
+ FunctionsSchedule,
GraphQL,
Health,
Locale,
@@ -128,10 +129,10 @@ jobs:
steps:
- name: checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Load Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
@@ -141,7 +142,7 @@ jobs:
run: |
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
- sleep 25
+ sleep 30
- name: Run ${{matrix.service}} Tests
run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
@@ -149,15 +150,15 @@ jobs:
- name: Run ${{matrix.service}} Shared Tables Tests
run: _APP_DATABASE_SHARED_TABLES=database_db_main docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
- benchamrking:
+ benchmarking:
name: Benchmark
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Load Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d3a7d060b0..b92361e51a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -319,10 +319,13 @@ These are the current metrics we collect usage stats for:
| users | Total number of users per project|
| executions | Total number of executions per project |
| databases | Total number of databases per project |
+| databases.storage | Total amount of storage used by all databases per project (in bytes) |
| collections | Total number of collections per project |
| {databaseInternalId}.collections | Total number of collections per database|
+| {databaseInternalId}.storage | Sum of database storage (in bytes) |
| documents | Total number of documents per project |
| {databaseInternalId}.{collectionInternalId}.documents | Total number of documents per collection |
+| {databaseInternalId}.{collectionInternalId}.storage | Sum of database storage used by the collection (in bytes) |
| buckets | Total number of buckets per project |
| files | Total number of files per project |
| {bucketInternalId}.files.storage | Sum of files.storage per bucket (in bytes) |
diff --git a/Dockerfile b/Dockerfile
index 22b37982d0..13b018df0f 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -28,6 +28,8 @@ 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
diff --git a/app/assets/security/10k-common-passwords b/app/assets/security/10k-common-passwords
index 6902dfb81a..487a4faf54 100644
--- a/app/assets/security/10k-common-passwords
+++ b/app/assets/security/10k-common-passwords
@@ -412,7 +412,6 @@ august
sammy
cool
brian
-brien
platinum
jake
bronco
@@ -1936,7 +1935,6 @@ panama
lucy
buffy
brianna
-brienna
welcome1
vette
blue22
@@ -3055,7 +3053,6 @@ randall
abstr
napster
brian1
-brien1
bogart
high
hitler
@@ -4126,7 +4123,6 @@ truman
cubbies
nitram
briana
-briena
ebony
kings
warner
diff --git a/app/cli.php b/app/cli.php
index ecff5180a2..23502ec402 100644
--- a/app/cli.php
+++ b/app/cli.php
@@ -197,8 +197,12 @@ CLI::setResource('logError', function (Registry $register) {
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
- $responseCode = $logger->addLog($log);
- Console::info('Usage stats log pushed with status code: ' . $responseCode);
+ try {
+ $responseCode = $logger->addLog($log);
+ Console::info('Error log pushed with status code: ' . $responseCode);
+ } catch (Throwable $th) {
+ Console::error('Error pushing log: ' . $th->getMessage());
+ }
}
Console::warning("Failed: {$error->getMessage()}");
diff --git a/app/config/collections.php b/app/config/collections.php
index 56c1761967..a55ab1abd0 100644
--- a/app/config/collections.php
+++ b/app/config/collections.php
@@ -2406,6 +2406,17 @@ $projectCollections = array_merge([
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('originalId'),
+ 'type' => Database::VAR_STRING,
+ 'signed' => true,
+ 'size' => Database::LENGTH_KEY,
+ 'format' => '',
+ 'filters' => [],
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ ],
],
'indexes' => [
[
@@ -4109,13 +4120,24 @@ $projectCollections = array_merge([
'$id' => ID::custom('source'),
'type' => Database::VAR_STRING,
'format' => '',
- 'size' => 8192,
+ 'size' => 8192, // reduce size
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('destination'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => Database::LENGTH_KEY,
+ 'signed' => true,
+ 'required' => false, // make true after patch script
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
[
'$id' => ID::custom('credentials'),
'type' => Database::VAR_STRING,
@@ -4508,6 +4530,28 @@ $consoleCollections = array_merge([
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('pingCount'),
+ 'type' => Database::VAR_INTEGER,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => false,
+ 'required' => false,
+ 'default' => 0,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('pingedAt'),
+ 'type' => Database::VAR_DATETIME,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => false,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['datetime'],
+ ]
],
'indexes' => [
[
@@ -4531,6 +4575,20 @@ $consoleCollections = array_merge([
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
+ [
+ '$id' => ID::custom('_key_pingCount'),
+ 'type' => Database::INDEX_KEY,
+ 'attributes' => ['pingCount'],
+ 'lengths' => [],
+ 'orders' => [],
+ ],
+ [
+ '$id' => ID::custom('_key_pingedAt'),
+ 'type' => Database::INDEX_KEY,
+ 'attributes' => ['pingedAt'],
+ 'lengths' => [],
+ 'orders' => [],
+ ]
],
],
diff --git a/app/config/errors.php b/app/config/errors.php
index fc79599b12..3afec4faaf 100644
--- a/app/config/errors.php
+++ b/app/config/errors.php
@@ -24,6 +24,11 @@ return [
'description' => 'Access to this API is forbidden.',
'code' => 401,
],
+ Exception::GENERAL_RESOURCE_BLOCKED => [
+ 'name' => Exception::GENERAL_RESOURCE_BLOCKED,
+ 'description' => 'Access to this resource is blocked.',
+ 'code' => 401,
+ ],
Exception::GENERAL_UNKNOWN_ORIGIN => [
'name' => Exception::GENERAL_UNKNOWN_ORIGIN,
'description' => 'The request originated from an unknown origin. If you trust this domain, please list it as a trusted platform in the Appwrite console.',
diff --git a/app/config/function-templates.php b/app/config/function-templates.php
index db26ff2c19..762c33dd9a 100644
--- a/app/config/function-templates.php
+++ b/app/config/function-templates.php
@@ -3,7 +3,7 @@
const TEMPLATE_RUNTIMES = [
'NODE' => [
'name' => 'node',
- 'versions' => ['21.0', '20.0', '19.0', '18.0', '16.0', '14.5']
+ 'versions' => ['22', '21.0', '20.0', '19.0', '18.0', '16.0', '14.5']
],
'PYTHON' => [
'name' => 'python',
@@ -11,7 +11,7 @@ const TEMPLATE_RUNTIMES = [
],
'DART' => [
'name' => 'dart',
- 'versions' => ['3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16', '2.16']
+ 'versions' => ['3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16', '2.16']
],
'GO' => [
'name' => 'go',
@@ -21,9 +21,13 @@ const TEMPLATE_RUNTIMES = [
'name' => 'php',
'versions' => ['8.3', '8.2', '8.1', '8.0']
],
+ 'DENO' => [
+ 'name' => 'deno',
+ 'versions' => ['2.0', '1.46', '1.40', '1.35', '1.24', '1.21']
+ ],
'BUN' => [
'name' => 'bun',
- 'versions' => ['1.0']
+ 'versions' => ['1.1', '1.0']
],
'RUBY' => [
'name' => 'ruby',
@@ -51,7 +55,7 @@ return [
'id' => 'starter',
'name' => 'Starter function',
'tagline' =>
- 'A simple function to get started. Edit this function to explore endless possibilities with Appwrite Functions.',
+ 'A simple function to get started. Edit this function to explore endless possibilities with Appwrite Functions.',
'permissions' => ['any'],
'events' => [],
'cron' => '',
@@ -73,6 +77,7 @@ return [
'src/index.php',
'php/starter'
),
+ ...getRuntimes(TEMPLATE_RUNTIMES['DENO'], 'deno cache src/main.ts', 'src/main.ts', 'deno/starter'),
...getRuntimes(TEMPLATE_RUNTIMES['BUN'], 'bun install', 'src/main.ts', 'bun/starter'),
...getRuntimes(TEMPLATE_RUNTIMES['RUBY'], 'bundle install', 'lib/main.rb', 'ruby/starter'),
],
@@ -121,7 +126,7 @@ return [
'description' => 'Authentication token to access your Upstash Vector database. Learn more.',
'value' => '',
'placeholder' =>
- 'oe4wNTbwHVLcDNa6oceZfhBEABsCNYh43ii6Xdq4bKBH7mq7qJkUmc4cs3ABbYyuVKWZTxVQjiNjYgydn2dkhABNes4NAuDpj7qxUAmZYqGJT78',
+ 'oe4wNTbwHVLcDNa6oceZfhBEABsCNYh43ii6Xdq4bKBH7mq7qJkUmc4cs3ABbYyuVKWZTxVQjiNjYgydn2dkhABNes4NAuDpj7qxUAmZYqGJT78',
'required' => true,
'type' => 'password'
]
@@ -227,7 +232,7 @@ return [
'id' => 'query-mongo-atlas',
'name' => 'Query MongoDB Atlas',
'tagline' =>
- 'Realtime NoSQL document database with geospecial, graph, search, and vector suport.',
+ 'Realtime NoSQL document database with geospecial, graph, search, and vector suport.',
'permissions' => ['any'],
'events' => [],
'cron' => '',
@@ -252,7 +257,7 @@ return [
'description' => 'The endpoint to connect to your Mongo database. Learn more.',
'value' => '',
'placeholder' =>
- 'mongodb+srv://appwrite:Yx42hafg7Q4fgkxe@cluster0.7mslfog.mongodb.net/?retryWrites=true&w=majority&appName=Appwrite',
+ 'mongodb+srv://appwrite:Yx42hafg7Q4fgkxe@cluster0.7mslfog.mongodb.net/?retryWrites=true&w=majority&appName=Appwrite',
'required' => true,
'type' => 'password'
]
@@ -264,7 +269,7 @@ return [
'id' => 'query-neon-postgres',
'name' => 'Query Neon Postgres',
'tagline' =>
- 'Reliable SQL database with replication, point-in-time recovery, and pgvector support.',
+ 'Reliable SQL database with replication, point-in-time recovery, and pgvector support.',
'permissions' => ['any'],
'events' => [],
'cron' => '',
@@ -491,7 +496,7 @@ return [
'id' => 'censor-with-redact',
'name' => 'Censor with Redact',
'tagline' =>
- 'Censor sensitive information from a provided text string using Redact API by Pangea.',
+ 'Censor sensitive information from a provided text string using Redact API by Pangea.',
'permissions' => ['any'],
'events' => [],
'cron' => '',
@@ -560,7 +565,7 @@ return [
'id' => 'github-issue-bot',
'name' => 'GitHub issue bot',
'tagline' =>
- 'Automate the process of responding to newly opened issues in a GitHub repository.',
+ 'Automate the process of responding to newly opened issues in a GitHub repository.',
'permissions' => ['any'],
'events' => [],
'cron' => '',
diff --git a/app/config/platforms.php b/app/config/platforms.php
index 40cea19fd3..e54fb0a073 100644
--- a/app/config/platforms.php
+++ b/app/config/platforms.php
@@ -1,9 +1,5 @@
[
'key' => APP_PLATFORM_CLIENT,
@@ -15,7 +11,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
- 'version' => '16.0.0',
+ 'version' => '16.0.2',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@@ -203,7 +199,7 @@ return [
[
'key' => 'web',
'name' => 'Console',
- 'version' => '1.1.0',
+ 'version' => '1.2.1',
'url' => 'https://github.com/appwrite/sdk-for-console',
'package' => '',
'enabled' => true,
@@ -285,7 +281,7 @@ return [
[
'key' => 'php',
'name' => 'PHP',
- 'version' => '12.0.0',
+ 'version' => '12.1.0',
'url' => 'https://github.com/appwrite/sdk-for-php',
'package' => 'https://packagist.org/packages/appwrite/appwrite',
'enabled' => true,
@@ -321,7 +317,7 @@ return [
[
'key' => 'ruby',
'name' => 'Ruby',
- 'version' => '12.1.0',
+ 'version' => '12.1.1',
'url' => 'https://github.com/appwrite/sdk-for-ruby',
'package' => 'https://rubygems.org/gems/appwrite',
'enabled' => true,
@@ -357,7 +353,7 @@ return [
[
'key' => 'dotnet',
'name' => '.NET',
- 'version' => '0.10.0',
+ 'version' => '0.10.1',
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
'package' => 'https://www.nuget.org/packages/Appwrite',
'enabled' => true,
diff --git a/app/config/regions.php b/app/config/regions.php
index b40667ab5e..61029a9996 100644
--- a/app/config/regions.php
+++ b/app/config/regions.php
@@ -31,7 +31,7 @@ return [
],
'blr' => [
'$id' => 'blr',
- 'name' => 'Banglore',
+ 'name' => 'Bengaluru',
'disabled' => true,
'flag' => 'in',
'default' => true,
diff --git a/app/config/roles.php b/app/config/roles.php
index 65b9643b89..fae97895b8 100644
--- a/app/config/roles.php
+++ b/app/config/roles.php
@@ -17,7 +17,6 @@ $member = [
'files.read',
'files.write',
'projects.read',
- 'projects.write',
'locale.read',
'avatars.read',
'execution.read',
@@ -49,6 +48,7 @@ $admins = [
'collections.write',
'platforms.read',
'platforms.write',
+ 'projects.write',
'keys.read',
'keys.write',
'webhooks.read',
@@ -75,7 +75,7 @@ $admins = [
'topics.write',
'topics.read',
'subscribers.write',
- 'subscribers.read'
+ 'subscribers.read',
];
return [
diff --git a/app/config/runtimes/specifications.php b/app/config/runtimes/specifications.php
index d3625db8a2..68880f4d4e 100644
--- a/app/config/runtimes/specifications.php
+++ b/app/config/runtimes/specifications.php
@@ -6,7 +6,7 @@ return [
Specification::S_05VCPU_512MB => [
'slug' => Specification::S_05VCPU_512MB,
'memory' => 512,
- 'cpus' => 0.5
+ 'cpus' => 1 // TODO: revert this, it's a temporary change to test function performance.
],
Specification::S_1VCPU_512MB => [
'slug' => Specification::S_1VCPU_512MB,
diff --git a/app/config/specs/open-api3-1.6.x-client.json b/app/config/specs/open-api3-1.6.x-client.json
index 8a9967090d..c00d4e2d07 100644
--- a/app/config/specs/open-api3-1.6.x-client.json
+++ b/app/config/specs/open-api3-1.6.x-client.json
@@ -43,7 +43,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 8,
+ "weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -94,7 +94,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 7,
+ "weight": 8,
"cookies": false,
"type": "",
"deprecated": false,
@@ -181,7 +181,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 33,
+ "weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -239,7 +239,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"tags": [
"account"
@@ -259,7 +259,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 56,
+ "weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -320,7 +320,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 57,
+ "weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -385,7 +385,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 28,
+ "weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -436,7 +436,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 30,
+ "weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -504,7 +504,7 @@
},
"x-appwrite": {
"method": "updateMFA",
- "weight": 43,
+ "weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -556,7 +556,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"tags": [
"account"
@@ -576,7 +576,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
- "weight": 45,
+ "weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -624,7 +624,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"tags": [
"account"
@@ -644,7 +644,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
- "weight": 46,
+ "weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -711,7 +711,7 @@
}
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"tags": [
"account"
@@ -724,7 +724,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 50,
+ "weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -774,7 +774,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"tags": [
"account"
@@ -794,7 +794,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
- "weight": 51,
+ "weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -850,7 +850,7 @@
}
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"tags": [
"account"
@@ -870,7 +870,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
- "weight": 52,
+ "weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -928,7 +928,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"tags": [
"account"
@@ -948,7 +948,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 44,
+ "weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -981,7 +981,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"tags": [
"account"
@@ -1001,7 +1001,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 49,
+ "weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1032,7 +1032,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"tags": [
"account"
@@ -1052,7 +1052,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 47,
+ "weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1083,7 +1083,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"tags": [
"account"
@@ -1103,7 +1103,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 48,
+ "weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1156,7 +1156,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 31,
+ "weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1228,7 +1228,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 32,
+ "weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1305,7 +1305,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 34,
+ "weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1383,7 +1383,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 29,
+ "weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1434,7 +1434,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 35,
+ "weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1506,7 +1506,7 @@
},
"x-appwrite": {
"method": "createRecovery",
- "weight": 37,
+ "weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1585,7 +1585,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
- "weight": 38,
+ "weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1669,7 +1669,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 10,
+ "weight": 11,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1713,7 +1713,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 11,
+ "weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1766,7 +1766,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
- "weight": 16,
+ "weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1817,7 +1817,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
- "weight": 15,
+ "weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1893,7 +1893,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
- "weight": 25,
+ "weight": 26,
"cookies": false,
"type": "",
"deprecated": true,
@@ -1962,7 +1962,7 @@
},
"x-appwrite": {
"method": "createOAuth2Session",
- "weight": 18,
+ "weight": 19,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2105,7 +2105,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
- "weight": 26,
+ "weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2181,7 +2181,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 17,
+ "weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2257,7 +2257,7 @@
},
"x-appwrite": {
"method": "getSession",
- "weight": 12,
+ "weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2320,7 +2320,7 @@
},
"x-appwrite": {
"method": "updateSession",
- "weight": 14,
+ "weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2376,7 +2376,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 13,
+ "weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2441,7 +2441,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 36,
+ "weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2494,7 +2494,7 @@
},
"x-appwrite": {
"method": "createPushTarget",
- "weight": 53,
+ "weight": 54,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2575,7 +2575,7 @@
},
"x-appwrite": {
"method": "updatePushTarget",
- "weight": 54,
+ "weight": 55,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2655,7 +2655,7 @@
},
"x-appwrite": {
"method": "deletePushTarget",
- "weight": 55,
+ "weight": 56,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2718,7 +2718,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
- "weight": 24,
+ "weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2799,7 +2799,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
- "weight": 23,
+ "weight": 24,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2881,7 +2881,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
- "weight": 22,
+ "weight": 23,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -3024,7 +3024,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
- "weight": 27,
+ "weight": 28,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3103,7 +3103,7 @@
},
"x-appwrite": {
"method": "createVerification",
- "weight": 39,
+ "weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3173,7 +3173,7 @@
},
"x-appwrite": {
"method": "updateVerification",
- "weight": 40,
+ "weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3251,7 +3251,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
- "weight": 41,
+ "weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3305,7 +3305,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 42,
+ "weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3376,7 +3376,7 @@
},
"x-appwrite": {
"method": "getBrowser",
- "weight": 59,
+ "weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3504,7 +3504,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
- "weight": 58,
+ "weight": 59,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3636,7 +3636,7 @@
},
"x-appwrite": {
"method": "getFavicon",
- "weight": 62,
+ "weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3696,7 +3696,7 @@
},
"x-appwrite": {
"method": "getFlag",
- "weight": 60,
+ "weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4186,7 +4186,7 @@
},
"x-appwrite": {
"method": "getImage",
- "weight": 61,
+ "weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4270,7 +4270,7 @@
},
"x-appwrite": {
"method": "getInitials",
- "weight": 64,
+ "weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4364,7 +4364,7 @@
},
"x-appwrite": {
"method": "getQR",
- "weight": 63,
+ "weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4465,7 +4465,7 @@
},
"x-appwrite": {
"method": "listDocuments",
- "weight": 108,
+ "weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4552,7 +4552,7 @@
},
"x-appwrite": {
"method": "createDocument",
- "weight": 107,
+ "weight": 108,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4661,7 +4661,7 @@
},
"x-appwrite": {
"method": "getDocument",
- "weight": 109,
+ "weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4758,7 +4758,7 @@
},
"x-appwrite": {
"method": "updateDocument",
- "weight": 111,
+ "weight": 112,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4859,7 +4859,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
- "weight": 112,
+ "weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4945,7 +4945,7 @@
},
"x-appwrite": {
"method": "listExecutions",
- "weight": 304,
+ "weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5033,7 +5033,7 @@
},
"x-appwrite": {
"method": "createExecution",
- "weight": 303,
+ "weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5084,7 +5084,7 @@
"body": {
"type": "string",
"description": "HTTP body of execution. Default value is empty string.",
- "x-example": null
+ "x-example": "
"
},
"async": {
"type": "boolean",
@@ -5150,7 +5150,7 @@
},
"x-appwrite": {
"method": "getExecution",
- "weight": 305,
+ "weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5226,7 +5226,7 @@
},
"x-appwrite": {
"method": "query",
- "weight": 329,
+ "weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5280,7 +5280,7 @@
},
"x-appwrite": {
"method": "mutation",
- "weight": 328,
+ "weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5334,7 +5334,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 116,
+ "weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5368,7 +5368,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"tags": [
"locale"
@@ -5388,7 +5388,7 @@
},
"x-appwrite": {
"method": "listCodes",
- "weight": 117,
+ "weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5442,7 +5442,7 @@
},
"x-appwrite": {
"method": "listContinents",
- "weight": 121,
+ "weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5496,7 +5496,7 @@
},
"x-appwrite": {
"method": "listCountries",
- "weight": 118,
+ "weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5550,7 +5550,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
- "weight": 119,
+ "weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5604,7 +5604,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
- "weight": 120,
+ "weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5658,7 +5658,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
- "weight": 122,
+ "weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5712,7 +5712,7 @@
},
"x-appwrite": {
"method": "listLanguages",
- "weight": 123,
+ "weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5766,7 +5766,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
- "weight": 380,
+ "weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5851,7 +5851,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
- "weight": 384,
+ "weight": 385,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5928,7 +5928,7 @@
},
"x-appwrite": {
"method": "listFiles",
- "weight": 206,
+ "weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6016,7 +6016,7 @@
},
"x-appwrite": {
"method": "createFile",
- "weight": 205,
+ "weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6116,7 +6116,7 @@
},
"x-appwrite": {
"method": "getFile",
- "weight": 207,
+ "weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6190,7 +6190,7 @@
},
"x-appwrite": {
"method": "updateFile",
- "weight": 212,
+ "weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6268,7 +6268,7 @@
}
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"tags": [
"storage"
@@ -6281,7 +6281,7 @@
},
"x-appwrite": {
"method": "deleteFile",
- "weight": 213,
+ "weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6350,7 +6350,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
- "weight": 209,
+ "weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6419,7 +6419,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
- "weight": 208,
+ "weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6610,7 +6610,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -6636,7 +6637,7 @@
},
"x-appwrite": {
"method": "getFileView",
- "weight": 210,
+ "weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6712,7 +6713,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 217,
+ "weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6790,7 +6791,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 216,
+ "weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6877,7 +6878,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 218,
+ "weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6941,7 +6942,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 220,
+ "weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7017,7 +7018,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 222,
+ "weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7083,7 +7084,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 224,
+ "weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7171,7 +7172,7 @@
},
"x-appwrite": {
"method": "createMembership",
- "weight": 223,
+ "weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7284,7 +7285,7 @@
},
"x-appwrite": {
"method": "getMembership",
- "weight": 225,
+ "weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7358,7 +7359,7 @@
},
"x-appwrite": {
"method": "updateMembership",
- "weight": 226,
+ "weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7447,7 +7448,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
- "weight": 228,
+ "weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7523,7 +7524,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
- "weight": 227,
+ "weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7623,7 +7624,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 219,
+ "weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7686,7 +7687,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 221,
+ "weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9405,7 +9406,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/open-api3-1.6.x-console.json b/app/config/specs/open-api3-1.6.x-console.json
index 07749889d8..87c61ada7b 100644
--- a/app/config/specs/open-api3-1.6.x-console.json
+++ b/app/config/specs/open-api3-1.6.x-console.json
@@ -43,7 +43,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 8,
+ "weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -93,7 +93,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 7,
+ "weight": 8,
"cookies": false,
"type": "",
"deprecated": false,
@@ -171,7 +171,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 9,
+ "weight": 10,
"cookies": false,
"type": "",
"deprecated": false,
@@ -221,7 +221,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 33,
+ "weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -278,7 +278,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"tags": [
"account"
@@ -298,7 +298,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 56,
+ "weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -358,7 +358,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 57,
+ "weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -422,7 +422,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 28,
+ "weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -473,7 +473,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 30,
+ "weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -540,7 +540,7 @@
},
"x-appwrite": {
"method": "updateMFA",
- "weight": 43,
+ "weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -591,7 +591,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"tags": [
"account"
@@ -611,7 +611,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
- "weight": 45,
+ "weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -658,7 +658,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"tags": [
"account"
@@ -678,7 +678,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
- "weight": 46,
+ "weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -744,7 +744,7 @@
}
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"tags": [
"account"
@@ -757,7 +757,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 50,
+ "weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -806,7 +806,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"tags": [
"account"
@@ -826,7 +826,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
- "weight": 51,
+ "weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -882,7 +882,7 @@
}
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"tags": [
"account"
@@ -902,7 +902,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
- "weight": 52,
+ "weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -959,7 +959,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"tags": [
"account"
@@ -979,7 +979,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 44,
+ "weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1011,7 +1011,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"tags": [
"account"
@@ -1031,7 +1031,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 49,
+ "weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1061,7 +1061,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"tags": [
"account"
@@ -1081,7 +1081,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 47,
+ "weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1111,7 +1111,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"tags": [
"account"
@@ -1131,7 +1131,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 48,
+ "weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1183,7 +1183,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 31,
+ "weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1254,7 +1254,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 32,
+ "weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1330,7 +1330,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 34,
+ "weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1407,7 +1407,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 29,
+ "weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1457,7 +1457,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 35,
+ "weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1528,7 +1528,7 @@
},
"x-appwrite": {
"method": "createRecovery",
- "weight": 37,
+ "weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1606,7 +1606,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
- "weight": 38,
+ "weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1689,7 +1689,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 10,
+ "weight": 11,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1732,7 +1732,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 11,
+ "weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1784,7 +1784,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
- "weight": 16,
+ "weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1835,7 +1835,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
- "weight": 15,
+ "weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1911,7 +1911,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
- "weight": 25,
+ "weight": 26,
"cookies": false,
"type": "",
"deprecated": true,
@@ -1980,7 +1980,7 @@
},
"x-appwrite": {
"method": "createOAuth2Session",
- "weight": 18,
+ "weight": 19,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2123,7 +2123,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
- "weight": 26,
+ "weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2199,7 +2199,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 17,
+ "weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2275,7 +2275,7 @@
},
"x-appwrite": {
"method": "getSession",
- "weight": 12,
+ "weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2337,7 +2337,7 @@
},
"x-appwrite": {
"method": "updateSession",
- "weight": 14,
+ "weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2392,7 +2392,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 13,
+ "weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2456,7 +2456,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 36,
+ "weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2508,7 +2508,7 @@
},
"x-appwrite": {
"method": "createPushTarget",
- "weight": 53,
+ "weight": 54,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2588,7 +2588,7 @@
},
"x-appwrite": {
"method": "updatePushTarget",
- "weight": 54,
+ "weight": 55,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2667,7 +2667,7 @@
},
"x-appwrite": {
"method": "deletePushTarget",
- "weight": 55,
+ "weight": 56,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2729,7 +2729,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
- "weight": 24,
+ "weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2810,7 +2810,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
- "weight": 23,
+ "weight": 24,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2892,7 +2892,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
- "weight": 22,
+ "weight": 23,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -3035,7 +3035,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
- "weight": 27,
+ "weight": 28,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3114,7 +3114,7 @@
},
"x-appwrite": {
"method": "createVerification",
- "weight": 39,
+ "weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3183,7 +3183,7 @@
},
"x-appwrite": {
"method": "updateVerification",
- "weight": 40,
+ "weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3260,7 +3260,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
- "weight": 41,
+ "weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3313,7 +3313,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 42,
+ "weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3383,7 +3383,7 @@
},
"x-appwrite": {
"method": "getBrowser",
- "weight": 59,
+ "weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3511,7 +3511,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
- "weight": 58,
+ "weight": 59,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3643,7 +3643,7 @@
},
"x-appwrite": {
"method": "getFavicon",
- "weight": 62,
+ "weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3703,7 +3703,7 @@
},
"x-appwrite": {
"method": "getFlag",
- "weight": 60,
+ "weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4193,7 +4193,7 @@
},
"x-appwrite": {
"method": "getImage",
- "weight": 61,
+ "weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4277,7 +4277,7 @@
},
"x-appwrite": {
"method": "getInitials",
- "weight": 64,
+ "weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4371,7 +4371,7 @@
},
"x-appwrite": {
"method": "getQR",
- "weight": 63,
+ "weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4452,7 +4452,7 @@
},
"\/console\/assistant": {
"post": {
- "summary": "Ask Query",
+ "summary": "Ask query",
"operationId": "assistantChat",
"tags": [
"assistant"
@@ -4465,7 +4465,7 @@
},
"x-appwrite": {
"method": "chat",
- "weight": 331,
+ "weight": 332,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4534,7 +4534,7 @@
},
"x-appwrite": {
"method": "variables",
- "weight": 330,
+ "weight": 331,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4584,7 +4584,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 69,
+ "weight": 70,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4659,7 +4659,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 68,
+ "weight": 69,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4740,7 +4740,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 113,
+ "weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4814,7 +4814,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 70,
+ "weight": 71,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4875,7 +4875,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 72,
+ "weight": 73,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4953,7 +4953,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 73,
+ "weight": 74,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5016,7 +5016,7 @@
},
"x-appwrite": {
"method": "listCollections",
- "weight": 75,
+ "weight": 76,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5101,7 +5101,7 @@
},
"x-appwrite": {
"method": "createCollection",
- "weight": 74,
+ "weight": 75,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5207,7 +5207,7 @@
},
"x-appwrite": {
"method": "getCollection",
- "weight": 76,
+ "weight": 77,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5278,7 +5278,7 @@
},
"x-appwrite": {
"method": "updateCollection",
- "weight": 78,
+ "weight": 79,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5379,7 +5379,7 @@
},
"x-appwrite": {
"method": "deleteCollection",
- "weight": 79,
+ "weight": 80,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5452,7 +5452,7 @@
},
"x-appwrite": {
"method": "listAttributes",
- "weight": 90,
+ "weight": 91,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5538,7 +5538,7 @@
},
"x-appwrite": {
"method": "createBooleanAttribute",
- "weight": 87,
+ "weight": 88,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5646,7 +5646,7 @@
},
"x-appwrite": {
"method": "updateBooleanAttribute",
- "weight": 99,
+ "weight": 100,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5759,7 +5759,7 @@
},
"x-appwrite": {
"method": "createDatetimeAttribute",
- "weight": 88,
+ "weight": 89,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5867,7 +5867,7 @@
},
"x-appwrite": {
"method": "updateDatetimeAttribute",
- "weight": 100,
+ "weight": 101,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5980,7 +5980,7 @@
},
"x-appwrite": {
"method": "createEmailAttribute",
- "weight": 81,
+ "weight": 82,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6088,7 +6088,7 @@
},
"x-appwrite": {
"method": "updateEmailAttribute",
- "weight": 93,
+ "weight": 94,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6201,7 +6201,7 @@
},
"x-appwrite": {
"method": "createEnumAttribute",
- "weight": 82,
+ "weight": 83,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6318,7 +6318,7 @@
},
"x-appwrite": {
"method": "updateEnumAttribute",
- "weight": 94,
+ "weight": 95,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6440,7 +6440,7 @@
},
"x-appwrite": {
"method": "createFloatAttribute",
- "weight": 86,
+ "weight": 87,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6558,7 +6558,7 @@
},
"x-appwrite": {
"method": "updateFloatAttribute",
- "weight": 98,
+ "weight": 99,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6683,7 +6683,7 @@
},
"x-appwrite": {
"method": "createIntegerAttribute",
- "weight": 85,
+ "weight": 86,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6801,7 +6801,7 @@
},
"x-appwrite": {
"method": "updateIntegerAttribute",
- "weight": 97,
+ "weight": 98,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6926,7 +6926,7 @@
},
"x-appwrite": {
"method": "createIpAttribute",
- "weight": 83,
+ "weight": 84,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7034,7 +7034,7 @@
},
"x-appwrite": {
"method": "updateIpAttribute",
- "weight": 95,
+ "weight": 96,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7147,7 +7147,7 @@
},
"x-appwrite": {
"method": "createRelationshipAttribute",
- "weight": 89,
+ "weight": 90,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7280,7 +7280,7 @@
},
"x-appwrite": {
"method": "createStringAttribute",
- "weight": 80,
+ "weight": 81,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7399,7 +7399,7 @@
},
"x-appwrite": {
"method": "updateStringAttribute",
- "weight": 92,
+ "weight": 93,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7517,7 +7517,7 @@
},
"x-appwrite": {
"method": "createUrlAttribute",
- "weight": 84,
+ "weight": 85,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7625,7 +7625,7 @@
},
"x-appwrite": {
"method": "updateUrlAttribute",
- "weight": 96,
+ "weight": 97,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7769,7 +7769,7 @@
},
"x-appwrite": {
"method": "getAttribute",
- "weight": 91,
+ "weight": 92,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7842,7 +7842,7 @@
},
"x-appwrite": {
"method": "deleteAttribute",
- "weight": 102,
+ "weight": 103,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7924,7 +7924,7 @@
},
"x-appwrite": {
"method": "updateRelationshipAttribute",
- "weight": 101,
+ "weight": 102,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8034,7 +8034,7 @@
},
"x-appwrite": {
"method": "listDocuments",
- "weight": 108,
+ "weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8121,7 +8121,7 @@
},
"x-appwrite": {
"method": "createDocument",
- "weight": 107,
+ "weight": 108,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8230,7 +8230,7 @@
},
"x-appwrite": {
"method": "getDocument",
- "weight": 109,
+ "weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8327,7 +8327,7 @@
},
"x-appwrite": {
"method": "updateDocument",
- "weight": 111,
+ "weight": 112,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8428,7 +8428,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
- "weight": 112,
+ "weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8514,7 +8514,7 @@
},
"x-appwrite": {
"method": "listDocumentLogs",
- "weight": 110,
+ "weight": 111,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8609,7 +8609,7 @@
},
"x-appwrite": {
"method": "listIndexes",
- "weight": 104,
+ "weight": 105,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8693,7 +8693,7 @@
},
"x-appwrite": {
"method": "createIndex",
- "weight": 103,
+ "weight": 104,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8815,7 +8815,7 @@
},
"x-appwrite": {
"method": "getIndex",
- "weight": 105,
+ "weight": 106,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8888,7 +8888,7 @@
},
"x-appwrite": {
"method": "deleteIndex",
- "weight": 106,
+ "weight": 107,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8970,7 +8970,7 @@
},
"x-appwrite": {
"method": "listCollectionLogs",
- "weight": 77,
+ "weight": 78,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9055,7 +9055,7 @@
},
"x-appwrite": {
"method": "getCollectionUsage",
- "weight": 115,
+ "weight": 116,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9149,7 +9149,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 71,
+ "weight": 72,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9224,7 +9224,7 @@
},
"x-appwrite": {
"method": "getDatabaseUsage",
- "weight": 114,
+ "weight": 115,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9308,7 +9308,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 287,
+ "weight": 288,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9383,7 +9383,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 286,
+ "weight": 287,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9437,6 +9437,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -9455,6 +9456,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -9462,23 +9465,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -9622,7 +9630,7 @@
},
"x-appwrite": {
"method": "listRuntimes",
- "weight": 288,
+ "weight": 289,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9673,7 +9681,7 @@
},
"x-appwrite": {
"method": "listSpecifications",
- "weight": 289,
+ "weight": 290,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9725,7 +9733,7 @@
},
"x-appwrite": {
"method": "listTemplates",
- "weight": 312,
+ "weight": 313,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9827,7 +9835,7 @@
},
"x-appwrite": {
"method": "getTemplate",
- "weight": 313,
+ "weight": 314,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9889,7 +9897,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 292,
+ "weight": 293,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9963,7 +9971,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 290,
+ "weight": 291,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10024,7 +10032,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 293,
+ "weight": 294,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10085,6 +10093,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -10103,6 +10112,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -10110,23 +10121,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -10240,7 +10256,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 296,
+ "weight": 297,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10303,7 +10319,7 @@
},
"x-appwrite": {
"method": "listDeployments",
- "weight": 298,
+ "weight": 299,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10388,7 +10404,7 @@
},
"x-appwrite": {
"method": "createDeployment",
- "weight": 297,
+ "weight": 298,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -10486,7 +10502,7 @@
},
"x-appwrite": {
"method": "getDeployment",
- "weight": 299,
+ "weight": 300,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10557,7 +10573,7 @@
},
"x-appwrite": {
"method": "updateDeployment",
- "weight": 295,
+ "weight": 296,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10621,7 +10637,7 @@
},
"x-appwrite": {
"method": "deleteDeployment",
- "weight": 300,
+ "weight": 301,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10687,7 +10703,7 @@
},
"x-appwrite": {
"method": "createBuild",
- "weight": 301,
+ "weight": 302,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10774,7 +10790,7 @@
},
"x-appwrite": {
"method": "updateDeploymentBuild",
- "weight": 302,
+ "weight": 303,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10840,7 +10856,7 @@
},
"x-appwrite": {
"method": "getDeploymentDownload",
- "weight": 294,
+ "weight": 295,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -10915,7 +10931,7 @@
},
"x-appwrite": {
"method": "listExecutions",
- "weight": 304,
+ "weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11003,7 +11019,7 @@
},
"x-appwrite": {
"method": "createExecution",
- "weight": 303,
+ "weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11054,7 +11070,7 @@
"body": {
"type": "string",
"description": "HTTP body of execution. Default value is empty string.",
- "x-example": null
+ "x-example": ""
},
"async": {
"type": "boolean",
@@ -11120,7 +11136,7 @@
},
"x-appwrite": {
"method": "getExecution",
- "weight": 305,
+ "weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11187,7 +11203,7 @@
},
"x-appwrite": {
"method": "deleteExecution",
- "weight": 306,
+ "weight": 307,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11260,7 +11276,7 @@
},
"x-appwrite": {
"method": "getFunctionUsage",
- "weight": 291,
+ "weight": 292,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11344,7 +11360,7 @@
},
"x-appwrite": {
"method": "listVariables",
- "weight": 308,
+ "weight": 309,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11405,7 +11421,7 @@
},
"x-appwrite": {
"method": "createVariable",
- "weight": 307,
+ "weight": 308,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11493,7 +11509,7 @@
},
"x-appwrite": {
"method": "getVariable",
- "weight": 309,
+ "weight": 310,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11564,7 +11580,7 @@
},
"x-appwrite": {
"method": "updateVariable",
- "weight": 310,
+ "weight": 311,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11652,7 +11668,7 @@
},
"x-appwrite": {
"method": "deleteVariable",
- "weight": 311,
+ "weight": 312,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11725,7 +11741,7 @@
},
"x-appwrite": {
"method": "query",
- "weight": 329,
+ "weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -11779,7 +11795,7 @@
},
"x-appwrite": {
"method": "mutation",
- "weight": 328,
+ "weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -11833,7 +11849,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 124,
+ "weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11884,7 +11900,7 @@
},
"x-appwrite": {
"method": "getAntivirus",
- "weight": 146,
+ "weight": 147,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11935,7 +11951,7 @@
},
"x-appwrite": {
"method": "getCache",
- "weight": 127,
+ "weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11986,7 +12002,7 @@
},
"x-appwrite": {
"method": "getCertificate",
- "weight": 133,
+ "weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12048,7 +12064,7 @@
},
"x-appwrite": {
"method": "getDB",
- "weight": 126,
+ "weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12099,7 +12115,7 @@
},
"x-appwrite": {
"method": "getPubSub",
- "weight": 129,
+ "weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12150,7 +12166,7 @@
},
"x-appwrite": {
"method": "getQueue",
- "weight": 128,
+ "weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12201,7 +12217,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
- "weight": 135,
+ "weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12265,7 +12281,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
- "weight": 134,
+ "weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12329,7 +12345,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
- "weight": 136,
+ "weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12404,7 +12420,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
- "weight": 137,
+ "weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12468,7 +12484,7 @@
},
"x-appwrite": {
"method": "getFailedJobs",
- "weight": 147,
+ "weight": 148,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12558,7 +12574,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
- "weight": 141,
+ "weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12622,7 +12638,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
- "weight": 132,
+ "weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12686,7 +12702,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
- "weight": 138,
+ "weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12750,7 +12766,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
- "weight": 139,
+ "weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12814,7 +12830,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
- "weight": 140,
+ "weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12878,7 +12894,7 @@
},
"x-appwrite": {
"method": "getQueueUsage",
- "weight": 142,
+ "weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12942,7 +12958,7 @@
},
"x-appwrite": {
"method": "getQueueUsageDump",
- "weight": 143,
+ "weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13006,7 +13022,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
- "weight": 131,
+ "weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13070,7 +13086,7 @@
},
"x-appwrite": {
"method": "getStorage",
- "weight": 145,
+ "weight": 146,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13121,7 +13137,7 @@
},
"x-appwrite": {
"method": "getStorageLocal",
- "weight": 144,
+ "weight": 145,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13172,7 +13188,7 @@
},
"x-appwrite": {
"method": "getTime",
- "weight": 130,
+ "weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13223,7 +13239,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 116,
+ "weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13257,7 +13273,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"tags": [
"locale"
@@ -13277,7 +13293,7 @@
},
"x-appwrite": {
"method": "listCodes",
- "weight": 117,
+ "weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13331,7 +13347,7 @@
},
"x-appwrite": {
"method": "listContinents",
- "weight": 121,
+ "weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13385,7 +13401,7 @@
},
"x-appwrite": {
"method": "listCountries",
- "weight": 118,
+ "weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13439,7 +13455,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
- "weight": 119,
+ "weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13493,7 +13509,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
- "weight": 120,
+ "weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13547,7 +13563,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
- "weight": 122,
+ "weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13601,7 +13617,7 @@
},
"x-appwrite": {
"method": "listLanguages",
- "weight": 123,
+ "weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13655,7 +13671,7 @@
},
"x-appwrite": {
"method": "listMessages",
- "weight": 388,
+ "weight": 389,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13733,7 +13749,7 @@
},
"x-appwrite": {
"method": "createEmail",
- "weight": 385,
+ "weight": 386,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13879,7 +13895,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 392,
+ "weight": 393,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14027,7 +14043,7 @@
},
"x-appwrite": {
"method": "createPush",
- "weight": 387,
+ "weight": 388,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14184,7 +14200,7 @@
},
"x-appwrite": {
"method": "updatePush",
- "weight": 394,
+ "weight": 395,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14343,7 +14359,7 @@
},
"x-appwrite": {
"method": "createSms",
- "weight": 386,
+ "weight": 387,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14454,7 +14470,7 @@
},
"x-appwrite": {
"method": "updateSms",
- "weight": 393,
+ "weight": 394,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14568,7 +14584,7 @@
},
"x-appwrite": {
"method": "getMessage",
- "weight": 391,
+ "weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14623,7 +14639,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 395,
+ "weight": 396,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14687,7 +14703,7 @@
},
"x-appwrite": {
"method": "listMessageLogs",
- "weight": 389,
+ "weight": 390,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14764,7 +14780,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 390,
+ "weight": 391,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14841,7 +14857,7 @@
},
"x-appwrite": {
"method": "listProviders",
- "weight": 360,
+ "weight": 361,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14919,7 +14935,7 @@
},
"x-appwrite": {
"method": "createApnsProvider",
- "weight": 359,
+ "weight": 360,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15026,7 +15042,7 @@
},
"x-appwrite": {
"method": "updateApnsProvider",
- "weight": 372,
+ "weight": 373,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15136,7 +15152,7 @@
},
"x-appwrite": {
"method": "createFcmProvider",
- "weight": 358,
+ "weight": 359,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15223,7 +15239,7 @@
},
"x-appwrite": {
"method": "updateFcmProvider",
- "weight": 371,
+ "weight": 372,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15313,7 +15329,7 @@
},
"x-appwrite": {
"method": "createMailgunProvider",
- "weight": 350,
+ "weight": 351,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15430,7 +15446,7 @@
},
"x-appwrite": {
"method": "updateMailgunProvider",
- "weight": 363,
+ "weight": 364,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15550,7 +15566,7 @@
},
"x-appwrite": {
"method": "createMsg91Provider",
- "weight": 353,
+ "weight": 354,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15647,7 +15663,7 @@
},
"x-appwrite": {
"method": "updateMsg91Provider",
- "weight": 366,
+ "weight": 367,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15747,7 +15763,7 @@
},
"x-appwrite": {
"method": "createSendgridProvider",
- "weight": 351,
+ "weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15854,7 +15870,7 @@
},
"x-appwrite": {
"method": "updateSendgridProvider",
- "weight": 364,
+ "weight": 365,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15964,7 +15980,7 @@
},
"x-appwrite": {
"method": "createSmtpProvider",
- "weight": 352,
+ "weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16109,7 +16125,7 @@
},
"x-appwrite": {
"method": "updateSmtpProvider",
- "weight": 365,
+ "weight": 366,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16256,7 +16272,7 @@
},
"x-appwrite": {
"method": "createTelesignProvider",
- "weight": 354,
+ "weight": 355,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16353,7 +16369,7 @@
},
"x-appwrite": {
"method": "updateTelesignProvider",
- "weight": 367,
+ "weight": 368,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16453,7 +16469,7 @@
},
"x-appwrite": {
"method": "createTextmagicProvider",
- "weight": 355,
+ "weight": 356,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16550,7 +16566,7 @@
},
"x-appwrite": {
"method": "updateTextmagicProvider",
- "weight": 368,
+ "weight": 369,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16650,7 +16666,7 @@
},
"x-appwrite": {
"method": "createTwilioProvider",
- "weight": 356,
+ "weight": 357,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16747,7 +16763,7 @@
},
"x-appwrite": {
"method": "updateTwilioProvider",
- "weight": 369,
+ "weight": 370,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16847,7 +16863,7 @@
},
"x-appwrite": {
"method": "createVonageProvider",
- "weight": 357,
+ "weight": 358,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16944,7 +16960,7 @@
},
"x-appwrite": {
"method": "updateVonageProvider",
- "weight": 370,
+ "weight": 371,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17044,7 +17060,7 @@
},
"x-appwrite": {
"method": "getProvider",
- "weight": 362,
+ "weight": 363,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17099,7 +17115,7 @@
},
"x-appwrite": {
"method": "deleteProvider",
- "weight": 373,
+ "weight": 374,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17163,7 +17179,7 @@
},
"x-appwrite": {
"method": "listProviderLogs",
- "weight": 361,
+ "weight": 362,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17240,7 +17256,7 @@
},
"x-appwrite": {
"method": "listSubscriberLogs",
- "weight": 382,
+ "weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17317,7 +17333,7 @@
},
"x-appwrite": {
"method": "listTopics",
- "weight": 375,
+ "weight": 376,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17393,7 +17409,7 @@
},
"x-appwrite": {
"method": "createTopic",
- "weight": 374,
+ "weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17478,7 +17494,7 @@
},
"x-appwrite": {
"method": "getTopic",
- "weight": 377,
+ "weight": 378,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17540,7 +17556,7 @@
},
"x-appwrite": {
"method": "updateTopic",
- "weight": 378,
+ "weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17619,7 +17635,7 @@
},
"x-appwrite": {
"method": "deleteTopic",
- "weight": 379,
+ "weight": 380,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17683,7 +17699,7 @@
},
"x-appwrite": {
"method": "listTopicLogs",
- "weight": 376,
+ "weight": 377,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17760,7 +17776,7 @@
},
"x-appwrite": {
"method": "listSubscribers",
- "weight": 381,
+ "weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17846,7 +17862,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
- "weight": 380,
+ "weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17938,7 +17954,7 @@
},
"x-appwrite": {
"method": "getSubscriber",
- "weight": 383,
+ "weight": 384,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18003,7 +18019,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
- "weight": 384,
+ "weight": 385,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18060,7 +18076,7 @@
},
"\/migrations": {
"get": {
- "summary": "List Migrations",
+ "summary": "List migrations",
"operationId": "migrationsList",
"tags": [
"migrations"
@@ -18080,7 +18096,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 337,
+ "weight": 338,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18136,7 +18152,7 @@
},
"\/migrations\/appwrite": {
"post": {
- "summary": "Migrate Appwrite Data",
+ "summary": "Migrate Appwrite data",
"operationId": "migrationsCreateAppwriteMigration",
"tags": [
"migrations"
@@ -18156,7 +18172,7 @@
},
"x-appwrite": {
"method": "createAppwriteMigration",
- "weight": 332,
+ "weight": 333,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18226,7 +18242,7 @@
},
"\/migrations\/appwrite\/report": {
"get": {
- "summary": "Generate a report on Appwrite Data",
+ "summary": "Generate a report on Appwrite data",
"operationId": "migrationsGetAppwriteReport",
"tags": [
"migrations"
@@ -18246,7 +18262,7 @@
},
"x-appwrite": {
"method": "getAppwriteReport",
- "weight": 339,
+ "weight": 340,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18321,7 +18337,7 @@
},
"\/migrations\/firebase": {
"post": {
- "summary": "Migrate Firebase Data (Service Account)",
+ "summary": "Migrate Firebase data (Service Account)",
"operationId": "migrationsCreateFirebaseMigration",
"tags": [
"migrations"
@@ -18341,7 +18357,7 @@
},
"x-appwrite": {
"method": "createFirebaseMigration",
- "weight": 334,
+ "weight": 335,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18399,7 +18415,7 @@
},
"\/migrations\/firebase\/deauthorize": {
"get": {
- "summary": "Revoke Appwrite's authorization to access Firebase Projects",
+ "summary": "Revoke Appwrite's authorization to access Firebase projects",
"operationId": "migrationsDeleteFirebaseAuth",
"tags": [
"migrations"
@@ -18412,7 +18428,7 @@
},
"x-appwrite": {
"method": "deleteFirebaseAuth",
- "weight": 345,
+ "weight": 346,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18442,7 +18458,7 @@
},
"\/migrations\/firebase\/oauth": {
"post": {
- "summary": "Migrate Firebase Data (OAuth)",
+ "summary": "Migrate Firebase data (OAuth)",
"operationId": "migrationsCreateFirebaseOAuthMigration",
"tags": [
"migrations"
@@ -18462,7 +18478,7 @@
},
"x-appwrite": {
"method": "createFirebaseOAuthMigration",
- "weight": 333,
+ "weight": 334,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18520,7 +18536,7 @@
},
"\/migrations\/firebase\/projects": {
"get": {
- "summary": "List Firebase Projects",
+ "summary": "List Firebase projects",
"operationId": "migrationsListFirebaseProjects",
"tags": [
"migrations"
@@ -18540,7 +18556,7 @@
},
"x-appwrite": {
"method": "listFirebaseProjects",
- "weight": 344,
+ "weight": 345,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18570,7 +18586,7 @@
},
"\/migrations\/firebase\/report": {
"get": {
- "summary": "Generate a report on Firebase Data",
+ "summary": "Generate a report on Firebase data",
"operationId": "migrationsGetFirebaseReport",
"tags": [
"migrations"
@@ -18590,7 +18606,7 @@
},
"x-appwrite": {
"method": "getFirebaseReport",
- "weight": 340,
+ "weight": 341,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18644,7 +18660,7 @@
},
"\/migrations\/firebase\/report\/oauth": {
"get": {
- "summary": "Generate a report on Firebase Data using OAuth",
+ "summary": "Generate a report on Firebase data using OAuth",
"operationId": "migrationsGetFirebaseReportOAuth",
"tags": [
"migrations"
@@ -18664,7 +18680,7 @@
},
"x-appwrite": {
"method": "getFirebaseReportOAuth",
- "weight": 341,
+ "weight": 342,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18718,7 +18734,7 @@
},
"\/migrations\/nhost": {
"post": {
- "summary": "Migrate NHost Data",
+ "summary": "Migrate NHost data",
"operationId": "migrationsCreateNHostMigration",
"tags": [
"migrations"
@@ -18738,7 +18754,7 @@
},
"x-appwrite": {
"method": "createNHostMigration",
- "weight": 336,
+ "weight": 337,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18851,7 +18867,7 @@
},
"x-appwrite": {
"method": "getNHostReport",
- "weight": 347,
+ "weight": 348,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18966,7 +18982,7 @@
},
"\/migrations\/supabase": {
"post": {
- "summary": "Migrate Supabase Data",
+ "summary": "Migrate Supabase data",
"operationId": "migrationsCreateSupabaseMigration",
"tags": [
"migrations"
@@ -18986,7 +19002,7 @@
},
"x-appwrite": {
"method": "createSupabaseMigration",
- "weight": 335,
+ "weight": 336,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19093,7 +19109,7 @@
},
"x-appwrite": {
"method": "getSupabaseReport",
- "weight": 346,
+ "weight": 347,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19199,7 +19215,7 @@
},
"\/migrations\/{migrationId}": {
"get": {
- "summary": "Get Migration",
+ "summary": "Get migration",
"operationId": "migrationsGet",
"tags": [
"migrations"
@@ -19219,7 +19235,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 338,
+ "weight": 339,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19259,7 +19275,7 @@
]
},
"patch": {
- "summary": "Retry Migration",
+ "summary": "Retry migration",
"operationId": "migrationsRetry",
"tags": [
"migrations"
@@ -19279,7 +19295,7 @@
},
"x-appwrite": {
"method": "retry",
- "weight": 348,
+ "weight": 349,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19319,7 +19335,7 @@
]
},
"delete": {
- "summary": "Delete Migration",
+ "summary": "Delete migration",
"operationId": "migrationsDelete",
"tags": [
"migrations"
@@ -19332,7 +19348,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 349,
+ "weight": 350,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19394,7 +19410,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 194,
+ "weight": 195,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19464,7 +19480,7 @@
},
"\/project\/variables": {
"get": {
- "summary": "List Variables",
+ "summary": "List variables",
"operationId": "projectListVariables",
"tags": [
"project"
@@ -19484,7 +19500,7 @@
},
"x-appwrite": {
"method": "listVariables",
- "weight": 196,
+ "weight": 197,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19512,7 +19528,7 @@
]
},
"post": {
- "summary": "Create Variable",
+ "summary": "Create variable",
"operationId": "projectCreateVariable",
"tags": [
"project"
@@ -19532,7 +19548,7 @@
},
"x-appwrite": {
"method": "createVariable",
- "weight": 195,
+ "weight": 196,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19587,7 +19603,7 @@
},
"\/project\/variables\/{variableId}": {
"get": {
- "summary": "Get Variable",
+ "summary": "Get variable",
"operationId": "projectGetVariable",
"tags": [
"project"
@@ -19607,7 +19623,7 @@
},
"x-appwrite": {
"method": "getVariable",
- "weight": 197,
+ "weight": 198,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19647,7 +19663,7 @@
]
},
"put": {
- "summary": "Update Variable",
+ "summary": "Update variable",
"operationId": "projectUpdateVariable",
"tags": [
"project"
@@ -19667,7 +19683,7 @@
},
"x-appwrite": {
"method": "updateVariable",
- "weight": 198,
+ "weight": 199,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19731,7 +19747,7 @@
}
},
"delete": {
- "summary": "Delete Variable",
+ "summary": "Delete variable",
"operationId": "projectDeleteVariable",
"tags": [
"project"
@@ -19744,7 +19760,7 @@
},
"x-appwrite": {
"method": "deleteVariable",
- "weight": 199,
+ "weight": 200,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19806,7 +19822,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 150,
+ "weight": 151,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19880,7 +19896,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 149,
+ "weight": 150,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20017,7 +20033,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 151,
+ "weight": 152,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20077,7 +20093,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 152,
+ "weight": 153,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20194,7 +20210,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 168,
+ "weight": 169,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20256,7 +20272,7 @@
},
"x-appwrite": {
"method": "updateApiStatus",
- "weight": 156,
+ "weight": 157,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20350,7 +20366,7 @@
},
"x-appwrite": {
"method": "updateApiStatusAll",
- "weight": 157,
+ "weight": 158,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20431,7 +20447,7 @@
},
"x-appwrite": {
"method": "updateAuthDuration",
- "weight": 161,
+ "weight": 162,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20512,7 +20528,7 @@
},
"x-appwrite": {
"method": "updateAuthLimit",
- "weight": 160,
+ "weight": 161,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20593,7 +20609,7 @@
},
"x-appwrite": {
"method": "updateAuthSessionsLimit",
- "weight": 166,
+ "weight": 167,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20674,7 +20690,7 @@
},
"x-appwrite": {
"method": "updateMockNumbers",
- "weight": 167,
+ "weight": 168,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20758,7 +20774,7 @@
},
"x-appwrite": {
"method": "updateAuthPasswordDictionary",
- "weight": 164,
+ "weight": 165,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20839,7 +20855,7 @@
},
"x-appwrite": {
"method": "updateAuthPasswordHistory",
- "weight": 163,
+ "weight": 164,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20920,7 +20936,7 @@
},
"x-appwrite": {
"method": "updatePersonalDataCheck",
- "weight": 165,
+ "weight": 166,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21001,7 +21017,7 @@
},
"x-appwrite": {
"method": "updateSessionAlerts",
- "weight": 159,
+ "weight": 160,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21082,7 +21098,7 @@
},
"x-appwrite": {
"method": "updateAuthStatus",
- "weight": 162,
+ "weight": 163,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21184,7 +21200,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 180,
+ "weight": 181,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21273,7 +21289,7 @@
},
"x-appwrite": {
"method": "listKeys",
- "weight": 176,
+ "weight": 177,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21282,7 +21298,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21333,7 +21349,7 @@
},
"x-appwrite": {
"method": "createKey",
- "weight": 175,
+ "weight": 176,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21342,7 +21358,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21428,7 +21444,7 @@
},
"x-appwrite": {
"method": "getKey",
- "weight": 177,
+ "weight": 178,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21437,7 +21453,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21498,7 +21514,7 @@
},
"x-appwrite": {
"method": "updateKey",
- "weight": 178,
+ "weight": 179,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21507,7 +21523,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21594,7 +21610,7 @@
},
"x-appwrite": {
"method": "deleteKey",
- "weight": 179,
+ "weight": 180,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21603,7 +21619,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21666,7 +21682,7 @@
},
"x-appwrite": {
"method": "updateOAuth2",
- "weight": 158,
+ "weight": 159,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21805,7 +21821,7 @@
},
"x-appwrite": {
"method": "listPlatforms",
- "weight": 182,
+ "weight": 183,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21814,7 +21830,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -21865,7 +21881,7 @@
},
"x-appwrite": {
"method": "createPlatform",
- "weight": 181,
+ "weight": 182,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21874,7 +21890,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -21986,7 +22002,7 @@
},
"x-appwrite": {
"method": "getPlatform",
- "weight": 183,
+ "weight": 184,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21995,7 +22011,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -22056,7 +22072,7 @@
},
"x-appwrite": {
"method": "updatePlatform",
- "weight": 184,
+ "weight": 185,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22065,7 +22081,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22153,7 +22169,7 @@
},
"x-appwrite": {
"method": "deletePlatform",
- "weight": 185,
+ "weight": 186,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22162,7 +22178,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22225,7 +22241,7 @@
},
"x-appwrite": {
"method": "updateServiceStatus",
- "weight": 154,
+ "weight": 155,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22327,7 +22343,7 @@
},
"x-appwrite": {
"method": "updateServiceStatusAll",
- "weight": 155,
+ "weight": 156,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22408,7 +22424,7 @@
},
"x-appwrite": {
"method": "updateSmtp",
- "weight": 186,
+ "weight": 187,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22528,7 +22544,7 @@
},
"x-appwrite": {
"method": "createSmtpTest",
- "weight": 187,
+ "weight": 188,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22620,7 +22636,8 @@
"description": "Does SMTP server use secure connection",
"x-example": "tls",
"enum": [
- "tls"
+ "tls",
+ "ssl"
],
"x-enum-name": "SMTPSecure",
"x-enum-keys": []
@@ -22660,7 +22677,7 @@
},
"x-appwrite": {
"method": "updateTeam",
- "weight": 153,
+ "weight": 154,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22741,7 +22758,7 @@
},
"x-appwrite": {
"method": "getEmailTemplate",
- "weight": 189,
+ "weight": 190,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22967,7 +22984,7 @@
},
"x-appwrite": {
"method": "updateEmailTemplate",
- "weight": 191,
+ "weight": 192,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23233,7 +23250,7 @@
},
"x-appwrite": {
"method": "deleteEmailTemplate",
- "weight": 193,
+ "weight": 194,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23461,7 +23478,7 @@
},
"x-appwrite": {
"method": "getSmsTemplate",
- "weight": 188,
+ "weight": 189,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23684,7 +23701,7 @@
},
"x-appwrite": {
"method": "updateSmsTemplate",
- "weight": 190,
+ "weight": 191,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23926,7 +23943,7 @@
},
"x-appwrite": {
"method": "deleteSmsTemplate",
- "weight": 192,
+ "weight": 193,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24151,7 +24168,7 @@
},
"x-appwrite": {
"method": "listWebhooks",
- "weight": 170,
+ "weight": 171,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24211,7 +24228,7 @@
},
"x-appwrite": {
"method": "createWebhook",
- "weight": 169,
+ "weight": 170,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24328,7 +24345,7 @@
},
"x-appwrite": {
"method": "getWebhook",
- "weight": 171,
+ "weight": 172,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24398,7 +24415,7 @@
},
"x-appwrite": {
"method": "updateWebhook",
- "weight": 172,
+ "weight": 173,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24516,7 +24533,7 @@
},
"x-appwrite": {
"method": "deleteWebhook",
- "weight": 174,
+ "weight": 175,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24588,7 +24605,7 @@
},
"x-appwrite": {
"method": "updateWebhookSignature",
- "weight": 173,
+ "weight": 174,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24640,7 +24657,7 @@
},
"\/proxy\/rules": {
"get": {
- "summary": "List Rules",
+ "summary": "List rules",
"operationId": "proxyListRules",
"tags": [
"proxy"
@@ -24660,7 +24677,7 @@
},
"x-appwrite": {
"method": "listRules",
- "weight": 315,
+ "weight": 316,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24714,7 +24731,7 @@
]
},
"post": {
- "summary": "Create Rule",
+ "summary": "Create rule",
"operationId": "proxyCreateRule",
"tags": [
"proxy"
@@ -24734,7 +24751,7 @@
},
"x-appwrite": {
"method": "createRule",
- "weight": 314,
+ "weight": 315,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24800,7 +24817,7 @@
},
"\/proxy\/rules\/{ruleId}": {
"get": {
- "summary": "Get Rule",
+ "summary": "Get rule",
"operationId": "proxyGetRule",
"tags": [
"proxy"
@@ -24820,7 +24837,7 @@
},
"x-appwrite": {
"method": "getRule",
- "weight": 316,
+ "weight": 317,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24860,7 +24877,7 @@
]
},
"delete": {
- "summary": "Delete Rule",
+ "summary": "Delete rule",
"operationId": "proxyDeleteRule",
"tags": [
"proxy"
@@ -24873,7 +24890,7 @@
},
"x-appwrite": {
"method": "deleteRule",
- "weight": 317,
+ "weight": 318,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24915,7 +24932,7 @@
},
"\/proxy\/rules\/{ruleId}\/verification": {
"patch": {
- "summary": "Update Rule Verification Status",
+ "summary": "Update rule verification status",
"operationId": "proxyUpdateRuleVerification",
"tags": [
"proxy"
@@ -24935,7 +24952,7 @@
},
"x-appwrite": {
"method": "updateRuleVerification",
- "weight": 318,
+ "weight": 319,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24997,7 +25014,7 @@
},
"x-appwrite": {
"method": "listBuckets",
- "weight": 201,
+ "weight": 202,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25072,7 +25089,7 @@
},
"x-appwrite": {
"method": "createBucket",
- "weight": 200,
+ "weight": 201,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25201,7 +25218,7 @@
},
"x-appwrite": {
"method": "getBucket",
- "weight": 202,
+ "weight": 203,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25262,7 +25279,7 @@
},
"x-appwrite": {
"method": "updateBucket",
- "weight": 203,
+ "weight": 204,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25388,7 +25405,7 @@
},
"x-appwrite": {
"method": "deleteBucket",
- "weight": 204,
+ "weight": 205,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25451,7 +25468,7 @@
},
"x-appwrite": {
"method": "listFiles",
- "weight": 206,
+ "weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25539,7 +25556,7 @@
},
"x-appwrite": {
"method": "createFile",
- "weight": 205,
+ "weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -25639,7 +25656,7 @@
},
"x-appwrite": {
"method": "getFile",
- "weight": 207,
+ "weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25713,7 +25730,7 @@
},
"x-appwrite": {
"method": "updateFile",
- "weight": 212,
+ "weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25791,7 +25808,7 @@
}
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"tags": [
"storage"
@@ -25804,7 +25821,7 @@
},
"x-appwrite": {
"method": "deleteFile",
- "weight": 213,
+ "weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25873,7 +25890,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
- "weight": 209,
+ "weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -25942,7 +25959,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
- "weight": 208,
+ "weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -26133,7 +26150,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -26159,7 +26177,7 @@
},
"x-appwrite": {
"method": "getFileView",
- "weight": 210,
+ "weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -26235,7 +26253,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 214,
+ "weight": 215,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26309,7 +26327,7 @@
},
"x-appwrite": {
"method": "getBucketUsage",
- "weight": 215,
+ "weight": 216,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26393,7 +26411,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 217,
+ "weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26471,7 +26489,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 216,
+ "weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26558,7 +26576,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 218,
+ "weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26622,7 +26640,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 220,
+ "weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26698,7 +26716,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 222,
+ "weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26764,7 +26782,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 229,
+ "weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26839,7 +26857,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 224,
+ "weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26927,7 +26945,7 @@
},
"x-appwrite": {
"method": "createMembership",
- "weight": 223,
+ "weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27040,7 +27058,7 @@
},
"x-appwrite": {
"method": "getMembership",
- "weight": 225,
+ "weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27114,7 +27132,7 @@
},
"x-appwrite": {
"method": "updateMembership",
- "weight": 226,
+ "weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27203,7 +27221,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
- "weight": 228,
+ "weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27279,7 +27297,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
- "weight": 227,
+ "weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27378,7 +27396,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 219,
+ "weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27440,7 +27458,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 221,
+ "weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27523,7 +27541,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 239,
+ "weight": 240,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27598,7 +27616,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 230,
+ "weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27688,7 +27706,7 @@
},
"x-appwrite": {
"method": "createArgon2User",
- "weight": 233,
+ "weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27775,7 +27793,7 @@
},
"x-appwrite": {
"method": "createBcryptUser",
- "weight": 231,
+ "weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27842,7 +27860,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"tags": [
"users"
@@ -27862,7 +27880,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 247,
+ "weight": 248,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27932,7 +27950,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 270,
+ "weight": 271,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27995,7 +28013,7 @@
},
"x-appwrite": {
"method": "createMD5User",
- "weight": 232,
+ "weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28082,7 +28100,7 @@
},
"x-appwrite": {
"method": "createPHPassUser",
- "weight": 235,
+ "weight": 236,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28169,7 +28187,7 @@
},
"x-appwrite": {
"method": "createScryptUser",
- "weight": 236,
+ "weight": 237,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28286,7 +28304,7 @@
},
"x-appwrite": {
"method": "createScryptModifiedUser",
- "weight": 237,
+ "weight": 238,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28391,7 +28409,7 @@
},
"x-appwrite": {
"method": "createSHAUser",
- "weight": 234,
+ "weight": 235,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28498,7 +28516,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 272,
+ "weight": 273,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28572,7 +28590,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 240,
+ "weight": 241,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28626,7 +28644,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 268,
+ "weight": 269,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28689,7 +28707,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 253,
+ "weight": 254,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28771,7 +28789,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 271,
+ "weight": 272,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28855,7 +28873,7 @@
},
"x-appwrite": {
"method": "updateLabels",
- "weight": 249,
+ "weight": 250,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28940,7 +28958,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 245,
+ "weight": 246,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29016,7 +29034,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 244,
+ "weight": 245,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29079,7 +29097,7 @@
},
"x-appwrite": {
"method": "updateMfa",
- "weight": 258,
+ "weight": 259,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29141,7 +29159,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"tags": [
"users"
@@ -29161,7 +29179,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 263,
+ "weight": 264,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29219,7 +29237,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"tags": [
"users"
@@ -29239,7 +29257,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 259,
+ "weight": 260,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29282,7 +29300,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"tags": [
"users"
@@ -29302,7 +29320,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 260,
+ "weight": 261,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29343,7 +29361,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"tags": [
"users"
@@ -29363,7 +29381,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 262,
+ "weight": 263,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29404,7 +29422,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"tags": [
"users"
@@ -29424,7 +29442,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 261,
+ "weight": 262,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29487,7 +29505,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 251,
+ "weight": 252,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29569,7 +29587,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 252,
+ "weight": 253,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29651,7 +29669,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 254,
+ "weight": 255,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29733,7 +29751,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 241,
+ "weight": 242,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29794,7 +29812,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 256,
+ "weight": 257,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29876,7 +29894,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 243,
+ "weight": 244,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29937,7 +29955,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 264,
+ "weight": 265,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29991,7 +30009,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 267,
+ "weight": 268,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30047,7 +30065,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 266,
+ "weight": 267,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30120,7 +30138,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 248,
+ "weight": 249,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30182,7 +30200,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"tags": [
"users"
@@ -30202,7 +30220,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 246,
+ "weight": 247,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30257,7 +30275,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"tags": [
"users"
@@ -30277,7 +30295,7 @@
},
"x-appwrite": {
"method": "createTarget",
- "weight": 238,
+ "weight": 239,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30369,7 +30387,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"tags": [
"users"
@@ -30389,7 +30407,7 @@
},
"x-appwrite": {
"method": "getTarget",
- "weight": 242,
+ "weight": 243,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30441,7 +30459,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"tags": [
"users"
@@ -30461,7 +30479,7 @@
},
"x-appwrite": {
"method": "updateTarget",
- "weight": 257,
+ "weight": 258,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30552,7 +30570,7 @@
},
"x-appwrite": {
"method": "deleteTarget",
- "weight": 269,
+ "weight": 270,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30626,7 +30644,7 @@
},
"x-appwrite": {
"method": "createToken",
- "weight": 265,
+ "weight": 266,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30710,7 +30728,7 @@
},
"x-appwrite": {
"method": "updateEmailVerification",
- "weight": 255,
+ "weight": 256,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30792,7 +30810,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 250,
+ "weight": 251,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30854,7 +30872,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories": {
"get": {
- "summary": "List Repositories",
+ "summary": "List repositories",
"operationId": "vcsListRepositories",
"tags": [
"vcs"
@@ -30874,7 +30892,7 @@
},
"x-appwrite": {
"method": "listRepositories",
- "weight": 277,
+ "weight": 278,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30945,7 +30963,7 @@
},
"x-appwrite": {
"method": "createRepository",
- "weight": 278,
+ "weight": 279,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31032,7 +31050,7 @@
},
"x-appwrite": {
"method": "getRepository",
- "weight": 279,
+ "weight": 280,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31084,7 +31102,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches": {
"get": {
- "summary": "List Repository Branches",
+ "summary": "List repository branches",
"operationId": "vcsListRepositoryBranches",
"tags": [
"vcs"
@@ -31104,7 +31122,7 @@
},
"x-appwrite": {
"method": "listRepositoryBranches",
- "weight": 280,
+ "weight": 281,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31176,7 +31194,7 @@
},
"x-appwrite": {
"method": "getRepositoryContents",
- "weight": 275,
+ "weight": 276,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31259,7 +31277,7 @@
},
"x-appwrite": {
"method": "createRepositoryDetection",
- "weight": 276,
+ "weight": 277,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31340,7 +31358,7 @@
},
"x-appwrite": {
"method": "updateExternalDeployments",
- "weight": 285,
+ "weight": 286,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31431,7 +31449,7 @@
},
"x-appwrite": {
"method": "listInstallations",
- "weight": 282,
+ "weight": 283,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31507,7 +31525,7 @@
},
"x-appwrite": {
"method": "getInstallation",
- "weight": 283,
+ "weight": 284,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31547,7 +31565,7 @@
]
},
"delete": {
- "summary": "Delete Installation",
+ "summary": "Delete installation",
"operationId": "vcsDeleteInstallation",
"tags": [
"vcs"
@@ -31560,7 +31578,7 @@
},
"x-appwrite": {
"method": "deleteInstallation",
- "weight": 284,
+ "weight": 285,
"cookies": false,
"type": "",
"deprecated": false,
@@ -32946,6 +32964,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -32965,6 +32993,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -33003,6 +33033,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -33030,7 +33070,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -33068,6 +33110,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -33095,7 +33147,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -33133,6 +33187,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -33145,7 +33209,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -33183,6 +33249,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33201,6 +33277,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33239,6 +33317,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -33265,6 +33353,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -33304,6 +33394,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33322,6 +33422,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33360,6 +33462,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33378,6 +33490,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33416,6 +33530,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -33434,6 +33558,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33472,6 +33598,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -33509,6 +33645,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -33557,6 +33695,16 @@
},
"x-example": [],
"nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -33564,7 +33712,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -35589,7 +35739,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
@@ -35912,6 +36062,17 @@
"description": "SMTP server secure protocol",
"x-example": "tls"
},
+ "pingCount": {
+ "type": "integer",
+ "description": "Number of times the ping was received for this project.",
+ "x-example": 1,
+ "format": "int32"
+ },
+ "pingedAt": {
+ "type": "string",
+ "description": "Last ping datetime in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"authEmailPassword": {
"type": "boolean",
"description": "Email\/Password auth method status",
@@ -36039,6 +36200,8 @@
"smtpUsername",
"smtpPassword",
"smtpSecure",
+ "pingCount",
+ "pingedAt",
"authEmailPassword",
"authUsersAuthMagicURL",
"authEmailOtp",
@@ -36747,6 +36910,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total databases storage in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"databases": {
"type": "array",
"description": "Aggregated number of databases per period.",
@@ -36770,6 +36939,14 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "An array of the aggregated number of databases storage in bytes per period.",
+ "items": {
+ "$ref": "#\/components\/schemas\/metric"
+ },
+ "x-example": []
}
},
"required": [
@@ -36777,9 +36954,11 @@
"databasesTotal",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"databases",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageDatabase": {
@@ -36803,6 +36982,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total storage used in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"collections": {
"type": "array",
"description": "Aggregated number of collections per period.",
@@ -36818,14 +37003,24 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "Aggregated storage used in bytes per period.",
+ "items": {
+ "$ref": "#\/components\/schemas\/metric"
+ },
+ "x-example": []
}
},
"required": [
"range",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageCollection": {
@@ -37366,6 +37561,12 @@
"x-example": 0,
"format": "int32"
},
+ "databasesStorageTotal": {
+ "type": "integer",
+ "description": "Total aggregated sum of databases storage size (in bytes).",
+ "x-example": 0,
+ "format": "int32"
+ },
"usersTotal": {
"type": "integer",
"description": "Total aggregated number of users.",
@@ -37462,6 +37663,14 @@
},
"x-example": []
},
+ "databasesStorageBreakdown": {
+ "type": "array",
+ "description": "An array of the aggregated breakdown of storage usage by databases.",
+ "items": {
+ "$ref": "#\/components\/schemas\/metricBreakdown"
+ },
+ "x-example": []
+ },
"executionsMbSecondsBreakdown": {
"type": "array",
"description": "Aggregated breakdown in totals of execution mbSeconds by functions.",
@@ -37491,6 +37700,7 @@
"executionsTotal",
"documentsTotal",
"databasesTotal",
+ "databasesStorageTotal",
"usersTotal",
"filesStorageTotal",
"functionsStorageTotal",
@@ -37505,6 +37715,7 @@
"executions",
"executionsBreakdown",
"bucketsBreakdown",
+ "databasesStorageBreakdown",
"executionsMbSecondsBreakdown",
"buildsMbSecondsBreakdown",
"functionsStorageBreakdown"
@@ -38237,7 +38448,7 @@
},
"$createdAt": {
"type": "string",
- "description": "Variable creation date in ISO 8601 format.",
+ "description": "Migration creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"$updatedAt": {
diff --git a/app/config/specs/open-api3-1.6.x-server.json b/app/config/specs/open-api3-1.6.x-server.json
index ef41688ca8..44270f16af 100644
--- a/app/config/specs/open-api3-1.6.x-server.json
+++ b/app/config/specs/open-api3-1.6.x-server.json
@@ -43,7 +43,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 8,
+ "weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -95,7 +95,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 7,
+ "weight": 8,
"cookies": false,
"type": "",
"deprecated": false,
@@ -182,7 +182,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 33,
+ "weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -241,7 +241,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"tags": [
"account"
@@ -261,7 +261,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 56,
+ "weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -323,7 +323,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 57,
+ "weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -389,7 +389,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 28,
+ "weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -440,7 +440,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 30,
+ "weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -509,7 +509,7 @@
},
"x-appwrite": {
"method": "updateMFA",
- "weight": 43,
+ "weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -562,7 +562,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"tags": [
"account"
@@ -582,7 +582,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
- "weight": 45,
+ "weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -631,7 +631,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"tags": [
"account"
@@ -651,7 +651,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
- "weight": 46,
+ "weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -719,7 +719,7 @@
}
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"tags": [
"account"
@@ -732,7 +732,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 50,
+ "weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -783,7 +783,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"tags": [
"account"
@@ -803,7 +803,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
- "weight": 51,
+ "weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -859,7 +859,7 @@
}
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"tags": [
"account"
@@ -879,7 +879,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
- "weight": 52,
+ "weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -938,7 +938,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"tags": [
"account"
@@ -958,7 +958,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 44,
+ "weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -992,7 +992,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"tags": [
"account"
@@ -1012,7 +1012,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 49,
+ "weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1044,7 +1044,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"tags": [
"account"
@@ -1064,7 +1064,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 47,
+ "weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1096,7 +1096,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"tags": [
"account"
@@ -1116,7 +1116,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 48,
+ "weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1170,7 +1170,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 31,
+ "weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1243,7 +1243,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 32,
+ "weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1321,7 +1321,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 34,
+ "weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1400,7 +1400,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 29,
+ "weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1452,7 +1452,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 35,
+ "weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1525,7 +1525,7 @@
},
"x-appwrite": {
"method": "createRecovery",
- "weight": 37,
+ "weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1605,7 +1605,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
- "weight": 38,
+ "weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1690,7 +1690,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 10,
+ "weight": 11,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1735,7 +1735,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 11,
+ "weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1789,7 +1789,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
- "weight": 16,
+ "weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1840,7 +1840,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
- "weight": 15,
+ "weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1916,7 +1916,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
- "weight": 25,
+ "weight": 26,
"cookies": false,
"type": "",
"deprecated": true,
@@ -1992,7 +1992,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
- "weight": 26,
+ "weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2068,7 +2068,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 17,
+ "weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2144,7 +2144,7 @@
},
"x-appwrite": {
"method": "getSession",
- "weight": 12,
+ "weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2208,7 +2208,7 @@
},
"x-appwrite": {
"method": "updateSession",
- "weight": 14,
+ "weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2265,7 +2265,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 13,
+ "weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2331,7 +2331,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 36,
+ "weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2385,7 +2385,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
- "weight": 24,
+ "weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2466,7 +2466,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
- "weight": 23,
+ "weight": 24,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2548,7 +2548,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
- "weight": 22,
+ "weight": 23,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2691,7 +2691,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
- "weight": 27,
+ "weight": 28,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2770,7 +2770,7 @@
},
"x-appwrite": {
"method": "createVerification",
- "weight": 39,
+ "weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2841,7 +2841,7 @@
},
"x-appwrite": {
"method": "updateVerification",
- "weight": 40,
+ "weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2920,7 +2920,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
- "weight": 41,
+ "weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2975,7 +2975,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 42,
+ "weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3047,7 +3047,7 @@
},
"x-appwrite": {
"method": "getBrowser",
- "weight": 59,
+ "weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3177,7 +3177,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
- "weight": 58,
+ "weight": 59,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3311,7 +3311,7 @@
},
"x-appwrite": {
"method": "getFavicon",
- "weight": 62,
+ "weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3373,7 +3373,7 @@
},
"x-appwrite": {
"method": "getFlag",
- "weight": 60,
+ "weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3865,7 +3865,7 @@
},
"x-appwrite": {
"method": "getImage",
- "weight": 61,
+ "weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3951,7 +3951,7 @@
},
"x-appwrite": {
"method": "getInitials",
- "weight": 64,
+ "weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4047,7 +4047,7 @@
},
"x-appwrite": {
"method": "getQR",
- "weight": 63,
+ "weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4150,7 +4150,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 69,
+ "weight": 70,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4226,7 +4226,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 68,
+ "weight": 69,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4308,7 +4308,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 70,
+ "weight": 71,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4370,7 +4370,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 72,
+ "weight": 73,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4449,7 +4449,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 73,
+ "weight": 74,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4513,7 +4513,7 @@
},
"x-appwrite": {
"method": "listCollections",
- "weight": 75,
+ "weight": 76,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4599,7 +4599,7 @@
},
"x-appwrite": {
"method": "createCollection",
- "weight": 74,
+ "weight": 75,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4706,7 +4706,7 @@
},
"x-appwrite": {
"method": "getCollection",
- "weight": 76,
+ "weight": 77,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4778,7 +4778,7 @@
},
"x-appwrite": {
"method": "updateCollection",
- "weight": 78,
+ "weight": 79,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4880,7 +4880,7 @@
},
"x-appwrite": {
"method": "deleteCollection",
- "weight": 79,
+ "weight": 80,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4954,7 +4954,7 @@
},
"x-appwrite": {
"method": "listAttributes",
- "weight": 90,
+ "weight": 91,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5041,7 +5041,7 @@
},
"x-appwrite": {
"method": "createBooleanAttribute",
- "weight": 87,
+ "weight": 88,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5150,7 +5150,7 @@
},
"x-appwrite": {
"method": "updateBooleanAttribute",
- "weight": 99,
+ "weight": 100,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5264,7 +5264,7 @@
},
"x-appwrite": {
"method": "createDatetimeAttribute",
- "weight": 88,
+ "weight": 89,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5373,7 +5373,7 @@
},
"x-appwrite": {
"method": "updateDatetimeAttribute",
- "weight": 100,
+ "weight": 101,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5487,7 +5487,7 @@
},
"x-appwrite": {
"method": "createEmailAttribute",
- "weight": 81,
+ "weight": 82,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5596,7 +5596,7 @@
},
"x-appwrite": {
"method": "updateEmailAttribute",
- "weight": 93,
+ "weight": 94,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5710,7 +5710,7 @@
},
"x-appwrite": {
"method": "createEnumAttribute",
- "weight": 82,
+ "weight": 83,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5828,7 +5828,7 @@
},
"x-appwrite": {
"method": "updateEnumAttribute",
- "weight": 94,
+ "weight": 95,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5951,7 +5951,7 @@
},
"x-appwrite": {
"method": "createFloatAttribute",
- "weight": 86,
+ "weight": 87,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6070,7 +6070,7 @@
},
"x-appwrite": {
"method": "updateFloatAttribute",
- "weight": 98,
+ "weight": 99,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6196,7 +6196,7 @@
},
"x-appwrite": {
"method": "createIntegerAttribute",
- "weight": 85,
+ "weight": 86,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6315,7 +6315,7 @@
},
"x-appwrite": {
"method": "updateIntegerAttribute",
- "weight": 97,
+ "weight": 98,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6441,7 +6441,7 @@
},
"x-appwrite": {
"method": "createIpAttribute",
- "weight": 83,
+ "weight": 84,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6550,7 +6550,7 @@
},
"x-appwrite": {
"method": "updateIpAttribute",
- "weight": 95,
+ "weight": 96,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6664,7 +6664,7 @@
},
"x-appwrite": {
"method": "createRelationshipAttribute",
- "weight": 89,
+ "weight": 90,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6798,7 +6798,7 @@
},
"x-appwrite": {
"method": "createStringAttribute",
- "weight": 80,
+ "weight": 81,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6918,7 +6918,7 @@
},
"x-appwrite": {
"method": "updateStringAttribute",
- "weight": 92,
+ "weight": 93,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7037,7 +7037,7 @@
},
"x-appwrite": {
"method": "createUrlAttribute",
- "weight": 84,
+ "weight": 85,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7146,7 +7146,7 @@
},
"x-appwrite": {
"method": "updateUrlAttribute",
- "weight": 96,
+ "weight": 97,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7291,7 +7291,7 @@
},
"x-appwrite": {
"method": "getAttribute",
- "weight": 91,
+ "weight": 92,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7365,7 +7365,7 @@
},
"x-appwrite": {
"method": "deleteAttribute",
- "weight": 102,
+ "weight": 103,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7448,7 +7448,7 @@
},
"x-appwrite": {
"method": "updateRelationshipAttribute",
- "weight": 101,
+ "weight": 102,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7559,7 +7559,7 @@
},
"x-appwrite": {
"method": "listDocuments",
- "weight": 108,
+ "weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7648,7 +7648,7 @@
},
"x-appwrite": {
"method": "createDocument",
- "weight": 107,
+ "weight": 108,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7759,7 +7759,7 @@
},
"x-appwrite": {
"method": "getDocument",
- "weight": 109,
+ "weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7858,7 +7858,7 @@
},
"x-appwrite": {
"method": "updateDocument",
- "weight": 111,
+ "weight": 112,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7961,7 +7961,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
- "weight": 112,
+ "weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8049,7 +8049,7 @@
},
"x-appwrite": {
"method": "listIndexes",
- "weight": 104,
+ "weight": 105,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8134,7 +8134,7 @@
},
"x-appwrite": {
"method": "createIndex",
- "weight": 103,
+ "weight": 104,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8257,7 +8257,7 @@
},
"x-appwrite": {
"method": "getIndex",
- "weight": 105,
+ "weight": 106,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8331,7 +8331,7 @@
},
"x-appwrite": {
"method": "deleteIndex",
- "weight": 106,
+ "weight": 107,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8414,7 +8414,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 287,
+ "weight": 288,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8490,7 +8490,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 286,
+ "weight": 287,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8545,6 +8545,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -8563,6 +8564,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -8570,23 +8573,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -8730,7 +8738,7 @@
},
"x-appwrite": {
"method": "listRuntimes",
- "weight": 288,
+ "weight": 289,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8782,7 +8790,7 @@
},
"x-appwrite": {
"method": "listSpecifications",
- "weight": 289,
+ "weight": 290,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8835,7 +8843,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 290,
+ "weight": 291,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8897,7 +8905,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 293,
+ "weight": 294,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8959,6 +8967,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -8977,6 +8986,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -8984,23 +8995,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -9114,7 +9130,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 296,
+ "weight": 297,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9178,7 +9194,7 @@
},
"x-appwrite": {
"method": "listDeployments",
- "weight": 298,
+ "weight": 299,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9264,7 +9280,7 @@
},
"x-appwrite": {
"method": "createDeployment",
- "weight": 297,
+ "weight": 298,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -9363,7 +9379,7 @@
},
"x-appwrite": {
"method": "getDeployment",
- "weight": 299,
+ "weight": 300,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9435,7 +9451,7 @@
},
"x-appwrite": {
"method": "updateDeployment",
- "weight": 295,
+ "weight": 296,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9500,7 +9516,7 @@
},
"x-appwrite": {
"method": "deleteDeployment",
- "weight": 300,
+ "weight": 301,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9567,7 +9583,7 @@
},
"x-appwrite": {
"method": "createBuild",
- "weight": 301,
+ "weight": 302,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9655,7 +9671,7 @@
},
"x-appwrite": {
"method": "updateDeploymentBuild",
- "weight": 302,
+ "weight": 303,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9722,7 +9738,7 @@
},
"x-appwrite": {
"method": "getDeploymentDownload",
- "weight": 294,
+ "weight": 295,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -9798,7 +9814,7 @@
},
"x-appwrite": {
"method": "listExecutions",
- "weight": 304,
+ "weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9888,7 +9904,7 @@
},
"x-appwrite": {
"method": "createExecution",
- "weight": 303,
+ "weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9941,7 +9957,7 @@
"body": {
"type": "string",
"description": "HTTP body of execution. Default value is empty string.",
- "x-example": null
+ "x-example": ""
},
"async": {
"type": "boolean",
@@ -10007,7 +10023,7 @@
},
"x-appwrite": {
"method": "getExecution",
- "weight": 305,
+ "weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10076,7 +10092,7 @@
},
"x-appwrite": {
"method": "deleteExecution",
- "weight": 306,
+ "weight": 307,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10150,7 +10166,7 @@
},
"x-appwrite": {
"method": "listVariables",
- "weight": 308,
+ "weight": 309,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10212,7 +10228,7 @@
},
"x-appwrite": {
"method": "createVariable",
- "weight": 307,
+ "weight": 308,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10301,7 +10317,7 @@
},
"x-appwrite": {
"method": "getVariable",
- "weight": 309,
+ "weight": 310,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10373,7 +10389,7 @@
},
"x-appwrite": {
"method": "updateVariable",
- "weight": 310,
+ "weight": 311,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10462,7 +10478,7 @@
},
"x-appwrite": {
"method": "deleteVariable",
- "weight": 311,
+ "weight": 312,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10536,7 +10552,7 @@
},
"x-appwrite": {
"method": "query",
- "weight": 329,
+ "weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -10592,7 +10608,7 @@
},
"x-appwrite": {
"method": "mutation",
- "weight": 328,
+ "weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -10648,7 +10664,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 124,
+ "weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10700,7 +10716,7 @@
},
"x-appwrite": {
"method": "getAntivirus",
- "weight": 146,
+ "weight": 147,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10752,7 +10768,7 @@
},
"x-appwrite": {
"method": "getCache",
- "weight": 127,
+ "weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10804,7 +10820,7 @@
},
"x-appwrite": {
"method": "getCertificate",
- "weight": 133,
+ "weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10867,7 +10883,7 @@
},
"x-appwrite": {
"method": "getDB",
- "weight": 126,
+ "weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10919,7 +10935,7 @@
},
"x-appwrite": {
"method": "getPubSub",
- "weight": 129,
+ "weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10971,7 +10987,7 @@
},
"x-appwrite": {
"method": "getQueue",
- "weight": 128,
+ "weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11023,7 +11039,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
- "weight": 135,
+ "weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11088,7 +11104,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
- "weight": 134,
+ "weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11153,7 +11169,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
- "weight": 136,
+ "weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11229,7 +11245,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
- "weight": 137,
+ "weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11294,7 +11310,7 @@
},
"x-appwrite": {
"method": "getFailedJobs",
- "weight": 147,
+ "weight": 148,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11385,7 +11401,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
- "weight": 141,
+ "weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11450,7 +11466,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
- "weight": 132,
+ "weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11515,7 +11531,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
- "weight": 138,
+ "weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11580,7 +11596,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
- "weight": 139,
+ "weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11645,7 +11661,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
- "weight": 140,
+ "weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11710,7 +11726,7 @@
},
"x-appwrite": {
"method": "getQueueUsage",
- "weight": 142,
+ "weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11775,7 +11791,7 @@
},
"x-appwrite": {
"method": "getQueueUsageDump",
- "weight": 143,
+ "weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11840,7 +11856,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
- "weight": 131,
+ "weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11905,7 +11921,7 @@
},
"x-appwrite": {
"method": "getStorage",
- "weight": 145,
+ "weight": 146,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11957,7 +11973,7 @@
},
"x-appwrite": {
"method": "getStorageLocal",
- "weight": 144,
+ "weight": 145,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12009,7 +12025,7 @@
},
"x-appwrite": {
"method": "getTime",
- "weight": 130,
+ "weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12061,7 +12077,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 116,
+ "weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12097,7 +12113,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"tags": [
"locale"
@@ -12117,7 +12133,7 @@
},
"x-appwrite": {
"method": "listCodes",
- "weight": 117,
+ "weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12173,7 +12189,7 @@
},
"x-appwrite": {
"method": "listContinents",
- "weight": 121,
+ "weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12229,7 +12245,7 @@
},
"x-appwrite": {
"method": "listCountries",
- "weight": 118,
+ "weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12285,7 +12301,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
- "weight": 119,
+ "weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12341,7 +12357,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
- "weight": 120,
+ "weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12397,7 +12413,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
- "weight": 122,
+ "weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12453,7 +12469,7 @@
},
"x-appwrite": {
"method": "listLanguages",
- "weight": 123,
+ "weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12509,7 +12525,7 @@
},
"x-appwrite": {
"method": "listMessages",
- "weight": 388,
+ "weight": 389,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12588,7 +12604,7 @@
},
"x-appwrite": {
"method": "createEmail",
- "weight": 385,
+ "weight": 386,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12735,7 +12751,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 392,
+ "weight": 393,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12884,7 +12900,7 @@
},
"x-appwrite": {
"method": "createPush",
- "weight": 387,
+ "weight": 388,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13042,7 +13058,7 @@
},
"x-appwrite": {
"method": "updatePush",
- "weight": 394,
+ "weight": 395,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13202,7 +13218,7 @@
},
"x-appwrite": {
"method": "createSms",
- "weight": 386,
+ "weight": 387,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13314,7 +13330,7 @@
},
"x-appwrite": {
"method": "updateSms",
- "weight": 393,
+ "weight": 394,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13429,7 +13445,7 @@
},
"x-appwrite": {
"method": "getMessage",
- "weight": 391,
+ "weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13485,7 +13501,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 395,
+ "weight": 396,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13550,7 +13566,7 @@
},
"x-appwrite": {
"method": "listMessageLogs",
- "weight": 389,
+ "weight": 390,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13628,7 +13644,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 390,
+ "weight": 391,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13706,7 +13722,7 @@
},
"x-appwrite": {
"method": "listProviders",
- "weight": 360,
+ "weight": 361,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13785,7 +13801,7 @@
},
"x-appwrite": {
"method": "createApnsProvider",
- "weight": 359,
+ "weight": 360,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13893,7 +13909,7 @@
},
"x-appwrite": {
"method": "updateApnsProvider",
- "weight": 372,
+ "weight": 373,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14004,7 +14020,7 @@
},
"x-appwrite": {
"method": "createFcmProvider",
- "weight": 358,
+ "weight": 359,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14092,7 +14108,7 @@
},
"x-appwrite": {
"method": "updateFcmProvider",
- "weight": 371,
+ "weight": 372,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14183,7 +14199,7 @@
},
"x-appwrite": {
"method": "createMailgunProvider",
- "weight": 350,
+ "weight": 351,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14301,7 +14317,7 @@
},
"x-appwrite": {
"method": "updateMailgunProvider",
- "weight": 363,
+ "weight": 364,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14422,7 +14438,7 @@
},
"x-appwrite": {
"method": "createMsg91Provider",
- "weight": 353,
+ "weight": 354,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14520,7 +14536,7 @@
},
"x-appwrite": {
"method": "updateMsg91Provider",
- "weight": 366,
+ "weight": 367,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14621,7 +14637,7 @@
},
"x-appwrite": {
"method": "createSendgridProvider",
- "weight": 351,
+ "weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14729,7 +14745,7 @@
},
"x-appwrite": {
"method": "updateSendgridProvider",
- "weight": 364,
+ "weight": 365,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14840,7 +14856,7 @@
},
"x-appwrite": {
"method": "createSmtpProvider",
- "weight": 352,
+ "weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14986,7 +15002,7 @@
},
"x-appwrite": {
"method": "updateSmtpProvider",
- "weight": 365,
+ "weight": 366,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15134,7 +15150,7 @@
},
"x-appwrite": {
"method": "createTelesignProvider",
- "weight": 354,
+ "weight": 355,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15232,7 +15248,7 @@
},
"x-appwrite": {
"method": "updateTelesignProvider",
- "weight": 367,
+ "weight": 368,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15333,7 +15349,7 @@
},
"x-appwrite": {
"method": "createTextmagicProvider",
- "weight": 355,
+ "weight": 356,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15431,7 +15447,7 @@
},
"x-appwrite": {
"method": "updateTextmagicProvider",
- "weight": 368,
+ "weight": 369,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15532,7 +15548,7 @@
},
"x-appwrite": {
"method": "createTwilioProvider",
- "weight": 356,
+ "weight": 357,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15630,7 +15646,7 @@
},
"x-appwrite": {
"method": "updateTwilioProvider",
- "weight": 369,
+ "weight": 370,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15731,7 +15747,7 @@
},
"x-appwrite": {
"method": "createVonageProvider",
- "weight": 357,
+ "weight": 358,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15829,7 +15845,7 @@
},
"x-appwrite": {
"method": "updateVonageProvider",
- "weight": 370,
+ "weight": 371,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15930,7 +15946,7 @@
},
"x-appwrite": {
"method": "getProvider",
- "weight": 362,
+ "weight": 363,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15986,7 +16002,7 @@
},
"x-appwrite": {
"method": "deleteProvider",
- "weight": 373,
+ "weight": 374,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16051,7 +16067,7 @@
},
"x-appwrite": {
"method": "listProviderLogs",
- "weight": 361,
+ "weight": 362,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16129,7 +16145,7 @@
},
"x-appwrite": {
"method": "listSubscriberLogs",
- "weight": 382,
+ "weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16207,7 +16223,7 @@
},
"x-appwrite": {
"method": "listTopics",
- "weight": 375,
+ "weight": 376,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16284,7 +16300,7 @@
},
"x-appwrite": {
"method": "createTopic",
- "weight": 374,
+ "weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16370,7 +16386,7 @@
},
"x-appwrite": {
"method": "getTopic",
- "weight": 377,
+ "weight": 378,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16433,7 +16449,7 @@
},
"x-appwrite": {
"method": "updateTopic",
- "weight": 378,
+ "weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16513,7 +16529,7 @@
},
"x-appwrite": {
"method": "deleteTopic",
- "weight": 379,
+ "weight": 380,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16578,7 +16594,7 @@
},
"x-appwrite": {
"method": "listTopicLogs",
- "weight": 376,
+ "weight": 377,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16656,7 +16672,7 @@
},
"x-appwrite": {
"method": "listSubscribers",
- "weight": 381,
+ "weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16743,7 +16759,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
- "weight": 380,
+ "weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16837,7 +16853,7 @@
},
"x-appwrite": {
"method": "getSubscriber",
- "weight": 383,
+ "weight": 384,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16903,7 +16919,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
- "weight": 384,
+ "weight": 385,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16982,7 +16998,7 @@
},
"x-appwrite": {
"method": "listBuckets",
- "weight": 201,
+ "weight": 202,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17058,7 +17074,7 @@
},
"x-appwrite": {
"method": "createBucket",
- "weight": 200,
+ "weight": 201,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17188,7 +17204,7 @@
},
"x-appwrite": {
"method": "getBucket",
- "weight": 202,
+ "weight": 203,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17250,7 +17266,7 @@
},
"x-appwrite": {
"method": "updateBucket",
- "weight": 203,
+ "weight": 204,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17377,7 +17393,7 @@
},
"x-appwrite": {
"method": "deleteBucket",
- "weight": 204,
+ "weight": 205,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17441,7 +17457,7 @@
},
"x-appwrite": {
"method": "listFiles",
- "weight": 206,
+ "weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17531,7 +17547,7 @@
},
"x-appwrite": {
"method": "createFile",
- "weight": 205,
+ "weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -17633,7 +17649,7 @@
},
"x-appwrite": {
"method": "getFile",
- "weight": 207,
+ "weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17709,7 +17725,7 @@
},
"x-appwrite": {
"method": "updateFile",
- "weight": 212,
+ "weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17789,7 +17805,7 @@
}
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"tags": [
"storage"
@@ -17802,7 +17818,7 @@
},
"x-appwrite": {
"method": "deleteFile",
- "weight": 213,
+ "weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17873,7 +17889,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
- "weight": 209,
+ "weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -17944,7 +17960,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
- "weight": 208,
+ "weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -18137,7 +18153,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -18163,7 +18180,7 @@
},
"x-appwrite": {
"method": "getFileView",
- "weight": 210,
+ "weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -18241,7 +18258,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 217,
+ "weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18321,7 +18338,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 216,
+ "weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18410,7 +18427,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 218,
+ "weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18476,7 +18493,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 220,
+ "weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18554,7 +18571,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 222,
+ "weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18622,7 +18639,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 224,
+ "weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18712,7 +18729,7 @@
},
"x-appwrite": {
"method": "createMembership",
- "weight": 223,
+ "weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18827,7 +18844,7 @@
},
"x-appwrite": {
"method": "getMembership",
- "weight": 225,
+ "weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18903,7 +18920,7 @@
},
"x-appwrite": {
"method": "updateMembership",
- "weight": 226,
+ "weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18994,7 +19011,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
- "weight": 228,
+ "weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19072,7 +19089,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
- "weight": 227,
+ "weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19173,7 +19190,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 219,
+ "weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19237,7 +19254,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 221,
+ "weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19322,7 +19339,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 239,
+ "weight": 240,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19398,7 +19415,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 230,
+ "weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19489,7 +19506,7 @@
},
"x-appwrite": {
"method": "createArgon2User",
- "weight": 233,
+ "weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19577,7 +19594,7 @@
},
"x-appwrite": {
"method": "createBcryptUser",
- "weight": 231,
+ "weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19645,7 +19662,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"tags": [
"users"
@@ -19665,7 +19682,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 247,
+ "weight": 248,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19736,7 +19753,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 270,
+ "weight": 271,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19800,7 +19817,7 @@
},
"x-appwrite": {
"method": "createMD5User",
- "weight": 232,
+ "weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19888,7 +19905,7 @@
},
"x-appwrite": {
"method": "createPHPassUser",
- "weight": 235,
+ "weight": 236,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19976,7 +19993,7 @@
},
"x-appwrite": {
"method": "createScryptUser",
- "weight": 236,
+ "weight": 237,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20094,7 +20111,7 @@
},
"x-appwrite": {
"method": "createScryptModifiedUser",
- "weight": 237,
+ "weight": 238,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20200,7 +20217,7 @@
},
"x-appwrite": {
"method": "createSHAUser",
- "weight": 234,
+ "weight": 235,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20308,7 +20325,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 240,
+ "weight": 241,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20363,7 +20380,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 268,
+ "weight": 269,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20427,7 +20444,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 253,
+ "weight": 254,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20510,7 +20527,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 271,
+ "weight": 272,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20595,7 +20612,7 @@
},
"x-appwrite": {
"method": "updateLabels",
- "weight": 249,
+ "weight": 250,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20681,7 +20698,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 245,
+ "weight": 246,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20758,7 +20775,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 244,
+ "weight": 245,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20822,7 +20839,7 @@
},
"x-appwrite": {
"method": "updateMfa",
- "weight": 258,
+ "weight": 259,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20885,7 +20902,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"tags": [
"users"
@@ -20905,7 +20922,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 263,
+ "weight": 264,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20964,7 +20981,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"tags": [
"users"
@@ -20984,7 +21001,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 259,
+ "weight": 260,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21028,7 +21045,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"tags": [
"users"
@@ -21048,7 +21065,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 260,
+ "weight": 261,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21090,7 +21107,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"tags": [
"users"
@@ -21110,7 +21127,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 262,
+ "weight": 263,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21152,7 +21169,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"tags": [
"users"
@@ -21172,7 +21189,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 261,
+ "weight": 262,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21236,7 +21253,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 251,
+ "weight": 252,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21319,7 +21336,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 252,
+ "weight": 253,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21402,7 +21419,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 254,
+ "weight": 255,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21485,7 +21502,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 241,
+ "weight": 242,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21547,7 +21564,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 256,
+ "weight": 257,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21630,7 +21647,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 243,
+ "weight": 244,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21692,7 +21709,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 264,
+ "weight": 265,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21747,7 +21764,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 267,
+ "weight": 268,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21804,7 +21821,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 266,
+ "weight": 267,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21878,7 +21895,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 248,
+ "weight": 249,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21941,7 +21958,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"tags": [
"users"
@@ -21961,7 +21978,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 246,
+ "weight": 247,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22017,7 +22034,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"tags": [
"users"
@@ -22037,7 +22054,7 @@
},
"x-appwrite": {
"method": "createTarget",
- "weight": 238,
+ "weight": 239,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22130,7 +22147,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"tags": [
"users"
@@ -22150,7 +22167,7 @@
},
"x-appwrite": {
"method": "getTarget",
- "weight": 242,
+ "weight": 243,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22203,7 +22220,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"tags": [
"users"
@@ -22223,7 +22240,7 @@
},
"x-appwrite": {
"method": "updateTarget",
- "weight": 257,
+ "weight": 258,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22315,7 +22332,7 @@
},
"x-appwrite": {
"method": "deleteTarget",
- "weight": 269,
+ "weight": 270,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22390,7 +22407,7 @@
},
"x-appwrite": {
"method": "createToken",
- "weight": 265,
+ "weight": 266,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22475,7 +22492,7 @@
},
"x-appwrite": {
"method": "updateEmailVerification",
- "weight": 255,
+ "weight": 256,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22558,7 +22575,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 250,
+ "weight": 251,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23677,6 +23694,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -23696,6 +23723,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -23734,6 +23763,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -23761,7 +23800,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -23799,6 +23840,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -23826,7 +23877,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -23864,6 +23917,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -23876,7 +23939,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -23914,6 +23979,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -23932,6 +24007,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -23970,6 +24047,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -23996,6 +24083,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -24035,6 +24124,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24053,6 +24152,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24091,6 +24192,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24109,6 +24220,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24147,6 +24260,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -24165,6 +24288,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24203,6 +24328,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -24240,6 +24375,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -24288,6 +24425,16 @@
},
"x-example": [],
"nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -24295,7 +24442,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -25966,7 +26115,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json
index 8a9967090d..021ae27c45 100644
--- a/app/config/specs/open-api3-latest-client.json
+++ b/app/config/specs/open-api3-latest-client.json
@@ -166,7 +166,7 @@
"tags": [
"account"
],
- "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\n",
+ "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\r\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\r\n",
"responses": {
"200": {
"description": "User",
@@ -239,7 +239,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"tags": [
"account"
@@ -556,7 +556,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"tags": [
"account"
@@ -624,7 +624,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"tags": [
"account"
@@ -711,7 +711,7 @@
}
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"tags": [
"account"
@@ -774,7 +774,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"tags": [
"account"
@@ -850,7 +850,7 @@
}
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"tags": [
"account"
@@ -928,7 +928,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"tags": [
"account"
@@ -981,7 +981,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"tags": [
"account"
@@ -1032,7 +1032,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"tags": [
"account"
@@ -1083,7 +1083,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"tags": [
"account"
@@ -1570,7 +1570,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
+ "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
"responses": {
"200": {
"description": "Token",
@@ -1802,7 +1802,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Session",
@@ -1954,7 +1954,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\n\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\r\n\r\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"301": {
"description": "File"
@@ -2703,7 +2703,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2784,7 +2784,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"201": {
"description": "Token",
@@ -2873,7 +2873,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \n\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \r\n\r\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"301": {
"description": "File"
@@ -3009,7 +3009,7 @@
"tags": [
"account"
],
- "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -3088,7 +3088,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\n",
+ "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3368,7 +3368,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
+ "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
"responses": {
"200": {
"description": "Image"
@@ -3496,7 +3496,7 @@
"tags": [
"avatars"
],
- "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -3628,7 +3628,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image"
@@ -3688,7 +3688,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4178,7 +4178,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image"
@@ -4262,7 +4262,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\n\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\r\n\r\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4356,7 +4356,7 @@
"tags": [
"avatars"
],
- "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\n",
+ "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -5319,7 +5319,7 @@
"tags": [
"locale"
],
- "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\n\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
+ "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\r\n\r\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
"responses": {
"200": {
"description": "Locale",
@@ -5368,7 +5368,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"tags": [
"locale"
@@ -6001,7 +6001,7 @@
"tags": [
"storage"
],
- "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\n\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\n\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\n\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\n",
+ "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\r\n\r\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\r\n\r\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\r\n\r\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\r\n",
"responses": {
"201": {
"description": "File",
@@ -6268,7 +6268,7 @@
}
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"tags": [
"storage"
@@ -6610,7 +6610,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -7156,7 +7157,7 @@
"tags": [
"teams"
],
- "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\n\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\n\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \n\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\n",
+ "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\r\n\r\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\r\n\r\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \r\n\r\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\r\n",
"responses": {
"201": {
"description": "Membership",
@@ -7343,7 +7344,7 @@
"tags": [
"teams"
],
- "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\n",
+ "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -7508,7 +7509,7 @@
"tags": [
"teams"
],
- "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\n\nIf the request is successful, a session for the user is automatically created.\n",
+ "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\r\n\r\nIf the request is successful, a session for the user is automatically created.\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -9405,7 +9406,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json
index 07749889d8..04e7c76e13 100644
--- a/app/config/specs/open-api3-latest-console.json
+++ b/app/config/specs/open-api3-latest-console.json
@@ -206,7 +206,7 @@
"tags": [
"account"
],
- "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\n",
+ "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\r\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\r\n",
"responses": {
"200": {
"description": "User",
@@ -278,7 +278,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"tags": [
"account"
@@ -591,7 +591,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"tags": [
"account"
@@ -658,7 +658,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"tags": [
"account"
@@ -744,7 +744,7 @@
}
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"tags": [
"account"
@@ -806,7 +806,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"tags": [
"account"
@@ -882,7 +882,7 @@
}
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"tags": [
"account"
@@ -959,7 +959,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"tags": [
"account"
@@ -1011,7 +1011,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"tags": [
"account"
@@ -1061,7 +1061,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"tags": [
"account"
@@ -1111,7 +1111,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"tags": [
"account"
@@ -1591,7 +1591,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
+ "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
"responses": {
"200": {
"description": "Token",
@@ -1820,7 +1820,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Session",
@@ -1972,7 +1972,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\n\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\r\n\r\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"301": {
"description": "File"
@@ -2714,7 +2714,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2795,7 +2795,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"201": {
"description": "Token",
@@ -2884,7 +2884,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \n\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \r\n\r\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"301": {
"description": "File"
@@ -3020,7 +3020,7 @@
"tags": [
"account"
],
- "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -3099,7 +3099,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\n",
+ "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3375,7 +3375,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
+ "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
"responses": {
"200": {
"description": "Image"
@@ -3503,7 +3503,7 @@
"tags": [
"avatars"
],
- "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -3635,7 +3635,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image"
@@ -3695,7 +3695,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4185,7 +4185,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image"
@@ -4269,7 +4269,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\n\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\r\n\r\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4363,7 +4363,7 @@
"tags": [
"avatars"
],
- "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\n",
+ "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4452,7 +4452,7 @@
},
"\/console\/assistant": {
"post": {
- "summary": "Ask Query",
+ "summary": "Ask query",
"operationId": "assistantChat",
"tags": [
"assistant"
@@ -4644,7 +4644,7 @@
"tags": [
"databases"
],
- "description": "Create a new Database.\n",
+ "description": "Create a new Database.\r\n",
"responses": {
"201": {
"description": "Database",
@@ -5523,7 +5523,7 @@
"tags": [
"databases"
],
- "description": "Create a boolean attribute.\n",
+ "description": "Create a boolean attribute.\r\n",
"responses": {
"202": {
"description": "AttributeBoolean",
@@ -5965,7 +5965,7 @@
"tags": [
"databases"
],
- "description": "Create an email attribute.\n",
+ "description": "Create an email attribute.\r\n",
"responses": {
"202": {
"description": "AttributeEmail",
@@ -6073,7 +6073,7 @@
"tags": [
"databases"
],
- "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEmail",
@@ -6186,7 +6186,7 @@
"tags": [
"databases"
],
- "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \n",
+ "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \r\n",
"responses": {
"202": {
"description": "AttributeEnum",
@@ -6303,7 +6303,7 @@
"tags": [
"databases"
],
- "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEnum",
@@ -6425,7 +6425,7 @@
"tags": [
"databases"
],
- "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeFloat",
@@ -6543,7 +6543,7 @@
"tags": [
"databases"
],
- "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeFloat",
@@ -6668,7 +6668,7 @@
"tags": [
"databases"
],
- "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeInteger",
@@ -6786,7 +6786,7 @@
"tags": [
"databases"
],
- "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeInteger",
@@ -6911,7 +6911,7 @@
"tags": [
"databases"
],
- "description": "Create IP address attribute.\n",
+ "description": "Create IP address attribute.\r\n",
"responses": {
"202": {
"description": "AttributeIP",
@@ -7019,7 +7019,7 @@
"tags": [
"databases"
],
- "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeIP",
@@ -7132,7 +7132,7 @@
"tags": [
"databases"
],
- "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"202": {
"description": "AttributeRelationship",
@@ -7265,7 +7265,7 @@
"tags": [
"databases"
],
- "description": "Create a string attribute.\n",
+ "description": "Create a string attribute.\r\n",
"responses": {
"202": {
"description": "AttributeString",
@@ -7384,7 +7384,7 @@
"tags": [
"databases"
],
- "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeString",
@@ -7502,7 +7502,7 @@
"tags": [
"databases"
],
- "description": "Create a URL attribute.\n",
+ "description": "Create a URL attribute.\r\n",
"responses": {
"202": {
"description": "AttributeURL",
@@ -7610,7 +7610,7 @@
"tags": [
"databases"
],
- "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeURL",
@@ -7909,7 +7909,7 @@
"tags": [
"databases"
],
- "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"200": {
"description": "AttributeRelationship",
@@ -8678,7 +8678,7 @@
"tags": [
"databases"
],
- "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\nAttributes can be `key`, `fulltext`, and `unique`.",
+ "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\r\nAttributes can be `key`, `fulltext`, and `unique`.",
"responses": {
"202": {
"description": "Index",
@@ -9658,7 +9658,7 @@
"tags": [
"functions"
],
- "description": "List allowed function specifications for this instance.\n",
+ "description": "List allowed function specifications for this instance.\r\n",
"responses": {
"200": {
"description": "Specifications List",
@@ -10373,7 +10373,7 @@
"tags": [
"functions"
],
- "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\n\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.",
+ "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\r\n\r\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\r\n\r\nUse the \"command\" param to set the entrypoint used to execute your code.",
"responses": {
"202": {
"description": "Deployment",
@@ -11179,7 +11179,7 @@
"tags": [
"functions"
],
- "description": "Delete a function execution by its unique ID.\n",
+ "description": "Delete a function execution by its unique ID.\r\n",
"responses": {
"204": {
"description": "No content"
@@ -12453,7 +12453,7 @@
"tags": [
"health"
],
- "description": "Returns the amount of failed jobs in a given queue.\n",
+ "description": "Returns the amount of failed jobs in a given queue.\r\n",
"responses": {
"200": {
"description": "Health Queue",
@@ -13208,7 +13208,7 @@
"tags": [
"locale"
],
- "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\n\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
+ "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\r\n\r\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
"responses": {
"200": {
"description": "Locale",
@@ -13257,7 +13257,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"tags": [
"locale"
@@ -13864,7 +13864,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -14169,7 +14169,7 @@
"tags": [
"messaging"
],
- "description": "Update a push notification by its unique ID.\n",
+ "description": "Update a push notification by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -14439,7 +14439,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -14553,7 +14553,7 @@
"tags": [
"messaging"
],
- "description": "Get a message by its unique ID.\n",
+ "description": "Get a message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -17029,7 +17029,7 @@
"tags": [
"messaging"
],
- "description": "Get a provider by its unique ID.\n",
+ "description": "Get a provider by its unique ID.\r\n",
"responses": {
"200": {
"description": "Provider",
@@ -17463,7 +17463,7 @@
"tags": [
"messaging"
],
- "description": "Get a topic by its unique ID.\n",
+ "description": "Get a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -17525,7 +17525,7 @@
"tags": [
"messaging"
],
- "description": "Update a topic by its unique ID.\n",
+ "description": "Update a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -17923,7 +17923,7 @@
"tags": [
"messaging"
],
- "description": "Get a subscriber by its unique ID.\n",
+ "description": "Get a subscriber by its unique ID.\r\n",
"responses": {
"200": {
"description": "Subscriber",
@@ -18060,7 +18060,7 @@
},
"\/migrations": {
"get": {
- "summary": "List Migrations",
+ "summary": "List migrations",
"operationId": "migrationsList",
"tags": [
"migrations"
@@ -18136,7 +18136,7 @@
},
"\/migrations\/appwrite": {
"post": {
- "summary": "Migrate Appwrite Data",
+ "summary": "Migrate Appwrite data",
"operationId": "migrationsCreateAppwriteMigration",
"tags": [
"migrations"
@@ -18226,7 +18226,7 @@
},
"\/migrations\/appwrite\/report": {
"get": {
- "summary": "Generate a report on Appwrite Data",
+ "summary": "Generate a report on Appwrite data",
"operationId": "migrationsGetAppwriteReport",
"tags": [
"migrations"
@@ -18321,7 +18321,7 @@
},
"\/migrations\/firebase": {
"post": {
- "summary": "Migrate Firebase Data (Service Account)",
+ "summary": "Migrate Firebase data (Service Account)",
"operationId": "migrationsCreateFirebaseMigration",
"tags": [
"migrations"
@@ -18399,7 +18399,7 @@
},
"\/migrations\/firebase\/deauthorize": {
"get": {
- "summary": "Revoke Appwrite's authorization to access Firebase Projects",
+ "summary": "Revoke Appwrite's authorization to access Firebase projects",
"operationId": "migrationsDeleteFirebaseAuth",
"tags": [
"migrations"
@@ -18442,7 +18442,7 @@
},
"\/migrations\/firebase\/oauth": {
"post": {
- "summary": "Migrate Firebase Data (OAuth)",
+ "summary": "Migrate Firebase data (OAuth)",
"operationId": "migrationsCreateFirebaseOAuthMigration",
"tags": [
"migrations"
@@ -18520,7 +18520,7 @@
},
"\/migrations\/firebase\/projects": {
"get": {
- "summary": "List Firebase Projects",
+ "summary": "List Firebase projects",
"operationId": "migrationsListFirebaseProjects",
"tags": [
"migrations"
@@ -18570,7 +18570,7 @@
},
"\/migrations\/firebase\/report": {
"get": {
- "summary": "Generate a report on Firebase Data",
+ "summary": "Generate a report on Firebase data",
"operationId": "migrationsGetFirebaseReport",
"tags": [
"migrations"
@@ -18644,7 +18644,7 @@
},
"\/migrations\/firebase\/report\/oauth": {
"get": {
- "summary": "Generate a report on Firebase Data using OAuth",
+ "summary": "Generate a report on Firebase data using OAuth",
"operationId": "migrationsGetFirebaseReportOAuth",
"tags": [
"migrations"
@@ -18718,7 +18718,7 @@
},
"\/migrations\/nhost": {
"post": {
- "summary": "Migrate NHost Data",
+ "summary": "Migrate NHost data",
"operationId": "migrationsCreateNHostMigration",
"tags": [
"migrations"
@@ -18966,7 +18966,7 @@
},
"\/migrations\/supabase": {
"post": {
- "summary": "Migrate Supabase Data",
+ "summary": "Migrate Supabase data",
"operationId": "migrationsCreateSupabaseMigration",
"tags": [
"migrations"
@@ -19199,7 +19199,7 @@
},
"\/migrations\/{migrationId}": {
"get": {
- "summary": "Get Migration",
+ "summary": "Get migration",
"operationId": "migrationsGet",
"tags": [
"migrations"
@@ -19259,7 +19259,7 @@
]
},
"patch": {
- "summary": "Retry Migration",
+ "summary": "Retry migration",
"operationId": "migrationsRetry",
"tags": [
"migrations"
@@ -19319,7 +19319,7 @@
]
},
"delete": {
- "summary": "Delete Migration",
+ "summary": "Delete migration",
"operationId": "migrationsDelete",
"tags": [
"migrations"
@@ -19464,7 +19464,7 @@
},
"\/project\/variables": {
"get": {
- "summary": "List Variables",
+ "summary": "List variables",
"operationId": "projectListVariables",
"tags": [
"project"
@@ -19512,7 +19512,7 @@
]
},
"post": {
- "summary": "Create Variable",
+ "summary": "Create variable",
"operationId": "projectCreateVariable",
"tags": [
"project"
@@ -19587,7 +19587,7 @@
},
"\/project\/variables\/{variableId}": {
"get": {
- "summary": "Get Variable",
+ "summary": "Get variable",
"operationId": "projectGetVariable",
"tags": [
"project"
@@ -19647,7 +19647,7 @@
]
},
"put": {
- "summary": "Update Variable",
+ "summary": "Update variable",
"operationId": "projectUpdateVariable",
"tags": [
"project"
@@ -19731,7 +19731,7 @@
}
},
"delete": {
- "summary": "Delete Variable",
+ "summary": "Delete variable",
"operationId": "projectDeleteVariable",
"tags": [
"project"
@@ -21282,7 +21282,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21342,7 +21342,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21437,7 +21437,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21507,7 +21507,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21603,7 +21603,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21814,7 +21814,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -21874,7 +21874,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -21995,7 +21995,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -22065,7 +22065,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22162,7 +22162,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22620,7 +22620,8 @@
"description": "Does SMTP server use secure connection",
"x-example": "tls",
"enum": [
- "tls"
+ "tls",
+ "ssl"
],
"x-enum-name": "SMTPSecure",
"x-enum-keys": []
@@ -24640,7 +24641,7 @@
},
"\/proxy\/rules": {
"get": {
- "summary": "List Rules",
+ "summary": "List rules",
"operationId": "proxyListRules",
"tags": [
"proxy"
@@ -24714,7 +24715,7 @@
]
},
"post": {
- "summary": "Create Rule",
+ "summary": "Create rule",
"operationId": "proxyCreateRule",
"tags": [
"proxy"
@@ -24800,7 +24801,7 @@
},
"\/proxy\/rules\/{ruleId}": {
"get": {
- "summary": "Get Rule",
+ "summary": "Get rule",
"operationId": "proxyGetRule",
"tags": [
"proxy"
@@ -24860,7 +24861,7 @@
]
},
"delete": {
- "summary": "Delete Rule",
+ "summary": "Delete rule",
"operationId": "proxyDeleteRule",
"tags": [
"proxy"
@@ -24915,7 +24916,7 @@
},
"\/proxy\/rules\/{ruleId}\/verification": {
"patch": {
- "summary": "Update Rule Verification Status",
+ "summary": "Update rule verification status",
"operationId": "proxyUpdateRuleVerification",
"tags": [
"proxy"
@@ -25524,7 +25525,7 @@
"tags": [
"storage"
],
- "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\n\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\n\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\n\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\n",
+ "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\r\n\r\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\r\n\r\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\r\n\r\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\r\n",
"responses": {
"201": {
"description": "File",
@@ -25791,7 +25792,7 @@
}
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"tags": [
"storage"
@@ -26133,7 +26134,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -26912,7 +26914,7 @@
"tags": [
"teams"
],
- "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\n\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\n\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \n\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\n",
+ "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\r\n\r\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\r\n\r\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \r\n\r\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\r\n",
"responses": {
"201": {
"description": "Membership",
@@ -27099,7 +27101,7 @@
"tags": [
"teams"
],
- "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\n",
+ "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -27264,7 +27266,7 @@
"tags": [
"teams"
],
- "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\n\nIf the request is successful, a session for the user is automatically created.\n",
+ "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\r\n\r\nIf the request is successful, a session for the user is automatically created.\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -27842,7 +27844,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"tags": [
"users"
@@ -28840,7 +28842,7 @@
"tags": [
"users"
],
- "description": "Update the user labels by its unique ID. \n\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
+ "description": "Update the user labels by its unique ID. \r\n\r\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
"responses": {
"200": {
"description": "User",
@@ -29141,7 +29143,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"tags": [
"users"
@@ -29219,7 +29221,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"tags": [
"users"
@@ -29282,7 +29284,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"tags": [
"users"
@@ -29343,7 +29345,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"tags": [
"users"
@@ -29404,7 +29406,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"tags": [
"users"
@@ -29922,7 +29924,7 @@
"tags": [
"users"
],
- "description": "Creates a session for a user. Returns an immediately usable session object.\n\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
+ "description": "Creates a session for a user. Returns an immediately usable session object.\r\n\r\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
"responses": {
"201": {
"description": "Session",
@@ -30182,7 +30184,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"tags": [
"users"
@@ -30257,7 +30259,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"tags": [
"users"
@@ -30369,7 +30371,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"tags": [
"users"
@@ -30441,7 +30443,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"tags": [
"users"
@@ -30611,7 +30613,7 @@
"tags": [
"users"
],
- "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\n",
+ "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -30854,7 +30856,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories": {
"get": {
- "summary": "List Repositories",
+ "summary": "List repositories",
"operationId": "vcsListRepositories",
"tags": [
"vcs"
@@ -31084,7 +31086,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches": {
"get": {
- "summary": "List Repository Branches",
+ "summary": "List repository branches",
"operationId": "vcsListRepositoryBranches",
"tags": [
"vcs"
@@ -31547,7 +31549,7 @@
]
},
"delete": {
- "summary": "Delete Installation",
+ "summary": "Delete installation",
"operationId": "vcsDeleteInstallation",
"tags": [
"vcs"
@@ -32946,6 +32948,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -32965,6 +32977,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -33003,6 +33017,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -33030,7 +33054,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -33068,6 +33094,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -33095,7 +33131,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -33133,6 +33171,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -33145,7 +33193,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -33183,6 +33233,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33201,6 +33261,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33239,6 +33301,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -33265,6 +33337,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -33304,6 +33378,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33322,6 +33406,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33360,6 +33446,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33378,6 +33474,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33416,6 +33514,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -33434,6 +33542,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33472,6 +33582,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -33509,6 +33629,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -33557,6 +33679,16 @@
},
"x-example": [],
"nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -33564,7 +33696,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -35589,7 +35723,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
@@ -36747,6 +36881,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total databases storage in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"databases": {
"type": "array",
"description": "Aggregated number of databases per period.",
@@ -36770,6 +36910,14 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "An array of the aggregated number of databases storage in bytes per period.",
+ "items": {
+ "$ref": "#\/components\/schemas\/metric"
+ },
+ "x-example": []
}
},
"required": [
@@ -36777,9 +36925,11 @@
"databasesTotal",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"databases",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageDatabase": {
@@ -36803,6 +36953,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total storage used in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"collections": {
"type": "array",
"description": "Aggregated number of collections per period.",
@@ -36818,14 +36974,24 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "Aggregated storage used in bytes per period.",
+ "items": {
+ "$ref": "#\/components\/schemas\/metric"
+ },
+ "x-example": []
}
},
"required": [
"range",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageCollection": {
@@ -37366,6 +37532,12 @@
"x-example": 0,
"format": "int32"
},
+ "databasesStorageTotal": {
+ "type": "integer",
+ "description": "Total aggregated sum of databases storage size (in bytes).",
+ "x-example": 0,
+ "format": "int32"
+ },
"usersTotal": {
"type": "integer",
"description": "Total aggregated number of users.",
@@ -37462,6 +37634,14 @@
},
"x-example": []
},
+ "databasesStorageBreakdown": {
+ "type": "array",
+ "description": "An array of the aggregated breakdown of storage usage by databases.",
+ "items": {
+ "$ref": "#\/components\/schemas\/metricBreakdown"
+ },
+ "x-example": []
+ },
"executionsMbSecondsBreakdown": {
"type": "array",
"description": "Aggregated breakdown in totals of execution mbSeconds by functions.",
@@ -37491,6 +37671,7 @@
"executionsTotal",
"documentsTotal",
"databasesTotal",
+ "databasesStorageTotal",
"usersTotal",
"filesStorageTotal",
"functionsStorageTotal",
@@ -37505,6 +37686,7 @@
"executions",
"executionsBreakdown",
"bucketsBreakdown",
+ "databasesStorageBreakdown",
"executionsMbSecondsBreakdown",
"buildsMbSecondsBreakdown",
"functionsStorageBreakdown"
diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json
index ef41688ca8..274eac9686 100644
--- a/app/config/specs/open-api3-latest-server.json
+++ b/app/config/specs/open-api3-latest-server.json
@@ -167,7 +167,7 @@
"tags": [
"account"
],
- "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\n",
+ "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\r\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\r\n",
"responses": {
"200": {
"description": "User",
@@ -241,7 +241,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"tags": [
"account"
@@ -562,7 +562,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"tags": [
"account"
@@ -631,7 +631,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"tags": [
"account"
@@ -719,7 +719,7 @@
}
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"tags": [
"account"
@@ -783,7 +783,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"tags": [
"account"
@@ -859,7 +859,7 @@
}
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"tags": [
"account"
@@ -938,7 +938,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"tags": [
"account"
@@ -992,7 +992,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"tags": [
"account"
@@ -1044,7 +1044,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"tags": [
"account"
@@ -1096,7 +1096,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"tags": [
"account"
@@ -1590,7 +1590,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
+ "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
"responses": {
"200": {
"description": "Token",
@@ -1825,7 +1825,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Session",
@@ -2370,7 +2370,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2451,7 +2451,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"201": {
"description": "Token",
@@ -2540,7 +2540,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \n\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \r\n\r\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"301": {
"description": "File"
@@ -2676,7 +2676,7 @@
"tags": [
"account"
],
- "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2755,7 +2755,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\n",
+ "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3039,7 +3039,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
+ "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
"responses": {
"200": {
"description": "Image"
@@ -3169,7 +3169,7 @@
"tags": [
"avatars"
],
- "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -3303,7 +3303,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image"
@@ -3365,7 +3365,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -3857,7 +3857,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image"
@@ -3943,7 +3943,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\n\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\r\n\r\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4039,7 +4039,7 @@
"tags": [
"avatars"
],
- "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\n",
+ "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\r\n",
"responses": {
"200": {
"description": "Image"
@@ -4211,7 +4211,7 @@
"tags": [
"databases"
],
- "description": "Create a new Database.\n",
+ "description": "Create a new Database.\r\n",
"responses": {
"201": {
"description": "Database",
@@ -5026,7 +5026,7 @@
"tags": [
"databases"
],
- "description": "Create a boolean attribute.\n",
+ "description": "Create a boolean attribute.\r\n",
"responses": {
"202": {
"description": "AttributeBoolean",
@@ -5472,7 +5472,7 @@
"tags": [
"databases"
],
- "description": "Create an email attribute.\n",
+ "description": "Create an email attribute.\r\n",
"responses": {
"202": {
"description": "AttributeEmail",
@@ -5581,7 +5581,7 @@
"tags": [
"databases"
],
- "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEmail",
@@ -5695,7 +5695,7 @@
"tags": [
"databases"
],
- "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \n",
+ "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \r\n",
"responses": {
"202": {
"description": "AttributeEnum",
@@ -5813,7 +5813,7 @@
"tags": [
"databases"
],
- "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEnum",
@@ -5936,7 +5936,7 @@
"tags": [
"databases"
],
- "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeFloat",
@@ -6055,7 +6055,7 @@
"tags": [
"databases"
],
- "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeFloat",
@@ -6181,7 +6181,7 @@
"tags": [
"databases"
],
- "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeInteger",
@@ -6300,7 +6300,7 @@
"tags": [
"databases"
],
- "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeInteger",
@@ -6426,7 +6426,7 @@
"tags": [
"databases"
],
- "description": "Create IP address attribute.\n",
+ "description": "Create IP address attribute.\r\n",
"responses": {
"202": {
"description": "AttributeIP",
@@ -6535,7 +6535,7 @@
"tags": [
"databases"
],
- "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeIP",
@@ -6649,7 +6649,7 @@
"tags": [
"databases"
],
- "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"202": {
"description": "AttributeRelationship",
@@ -6783,7 +6783,7 @@
"tags": [
"databases"
],
- "description": "Create a string attribute.\n",
+ "description": "Create a string attribute.\r\n",
"responses": {
"202": {
"description": "AttributeString",
@@ -6903,7 +6903,7 @@
"tags": [
"databases"
],
- "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeString",
@@ -7022,7 +7022,7 @@
"tags": [
"databases"
],
- "description": "Create a URL attribute.\n",
+ "description": "Create a URL attribute.\r\n",
"responses": {
"202": {
"description": "AttributeURL",
@@ -7131,7 +7131,7 @@
"tags": [
"databases"
],
- "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeURL",
@@ -7433,7 +7433,7 @@
"tags": [
"databases"
],
- "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"200": {
"description": "AttributeRelationship",
@@ -8119,7 +8119,7 @@
"tags": [
"databases"
],
- "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\nAttributes can be `key`, `fulltext`, and `unique`.",
+ "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\r\nAttributes can be `key`, `fulltext`, and `unique`.",
"responses": {
"202": {
"description": "Index",
@@ -8767,7 +8767,7 @@
"tags": [
"functions"
],
- "description": "List allowed function specifications for this instance.\n",
+ "description": "List allowed function specifications for this instance.\r\n",
"responses": {
"200": {
"description": "Specifications List",
@@ -9249,7 +9249,7 @@
"tags": [
"functions"
],
- "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\n\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.",
+ "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\r\n\r\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\r\n\r\nUse the \"command\" param to set the entrypoint used to execute your code.",
"responses": {
"202": {
"description": "Deployment",
@@ -10068,7 +10068,7 @@
"tags": [
"functions"
],
- "description": "Delete a function execution by its unique ID.\n",
+ "description": "Delete a function execution by its unique ID.\r\n",
"responses": {
"204": {
"description": "No content"
@@ -11279,7 +11279,7 @@
"tags": [
"health"
],
- "description": "Returns the amount of failed jobs in a given queue.\n",
+ "description": "Returns the amount of failed jobs in a given queue.\r\n",
"responses": {
"200": {
"description": "Health Queue",
@@ -12046,7 +12046,7 @@
"tags": [
"locale"
],
- "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\n\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
+ "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\r\n\r\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
"responses": {
"200": {
"description": "Locale",
@@ -12097,7 +12097,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"tags": [
"locale"
@@ -12720,7 +12720,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -13027,7 +13027,7 @@
"tags": [
"messaging"
],
- "description": "Update a push notification by its unique ID.\n",
+ "description": "Update a push notification by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -13299,7 +13299,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -13414,7 +13414,7 @@
"tags": [
"messaging"
],
- "description": "Get a message by its unique ID.\n",
+ "description": "Get a message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -15915,7 +15915,7 @@
"tags": [
"messaging"
],
- "description": "Get a provider by its unique ID.\n",
+ "description": "Get a provider by its unique ID.\r\n",
"responses": {
"200": {
"description": "Provider",
@@ -16355,7 +16355,7 @@
"tags": [
"messaging"
],
- "description": "Get a topic by its unique ID.\n",
+ "description": "Get a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -16418,7 +16418,7 @@
"tags": [
"messaging"
],
- "description": "Update a topic by its unique ID.\n",
+ "description": "Update a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -16822,7 +16822,7 @@
"tags": [
"messaging"
],
- "description": "Get a subscriber by its unique ID.\n",
+ "description": "Get a subscriber by its unique ID.\r\n",
"responses": {
"200": {
"description": "Subscriber",
@@ -17516,7 +17516,7 @@
"tags": [
"storage"
],
- "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\n\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\n\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\n\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\n",
+ "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\r\n\r\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\r\n\r\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\r\n\r\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\r\n",
"responses": {
"201": {
"description": "File",
@@ -17789,7 +17789,7 @@
}
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"tags": [
"storage"
@@ -18137,7 +18137,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -18697,7 +18698,7 @@
"tags": [
"teams"
],
- "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\n\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\n\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \n\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\n",
+ "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\r\n\r\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\r\n\r\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \r\n\r\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\r\n",
"responses": {
"201": {
"description": "Membership",
@@ -18888,7 +18889,7 @@
"tags": [
"teams"
],
- "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\n",
+ "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -19057,7 +19058,7 @@
"tags": [
"teams"
],
- "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\n\nIf the request is successful, a session for the user is automatically created.\n",
+ "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\r\n\r\nIf the request is successful, a session for the user is automatically created.\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -19645,7 +19646,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"tags": [
"users"
@@ -20580,7 +20581,7 @@
"tags": [
"users"
],
- "description": "Update the user labels by its unique ID. \n\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
+ "description": "Update the user labels by its unique ID. \r\n\r\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
"responses": {
"200": {
"description": "User",
@@ -20885,7 +20886,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"tags": [
"users"
@@ -20964,7 +20965,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"tags": [
"users"
@@ -21028,7 +21029,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"tags": [
"users"
@@ -21090,7 +21091,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"tags": [
"users"
@@ -21152,7 +21153,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"tags": [
"users"
@@ -21677,7 +21678,7 @@
"tags": [
"users"
],
- "description": "Creates a session for a user. Returns an immediately usable session object.\n\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
+ "description": "Creates a session for a user. Returns an immediately usable session object.\r\n\r\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
"responses": {
"201": {
"description": "Session",
@@ -21941,7 +21942,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"tags": [
"users"
@@ -22017,7 +22018,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"tags": [
"users"
@@ -22130,7 +22131,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"tags": [
"users"
@@ -22203,7 +22204,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"tags": [
"users"
@@ -22375,7 +22376,7 @@
"tags": [
"users"
],
- "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\n",
+ "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -23677,6 +23678,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -23696,6 +23707,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -23734,6 +23747,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -23761,7 +23784,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -23799,6 +23824,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -23826,7 +23861,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -23864,6 +23901,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -23876,7 +23923,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -23914,6 +23963,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -23932,6 +23991,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -23970,6 +24031,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -23996,6 +24067,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -24035,6 +24108,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24053,6 +24136,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24091,6 +24176,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24109,6 +24204,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24147,6 +24244,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -24165,6 +24272,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24203,6 +24312,16 @@
"x-example": false,
"nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -24240,6 +24359,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -24288,6 +24409,16 @@
},
"x-example": [],
"nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -24295,7 +24426,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -25966,7 +26099,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/swagger2-1.6.x-client.json b/app/config/specs/swagger2-1.6.x-client.json
index ce9ea857bb..f070b1a4b0 100644
--- a/app/config/specs/swagger2-1.6.x-client.json
+++ b/app/config/specs/swagger2-1.6.x-client.json
@@ -87,7 +87,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 8,
+ "weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -140,7 +140,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 7,
+ "weight": 8,
"cookies": false,
"type": "",
"deprecated": false,
@@ -233,7 +233,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 33,
+ "weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -293,7 +293,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"consumes": [
"application\/json"
@@ -315,7 +315,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 56,
+ "weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -379,7 +379,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 57,
+ "weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -444,7 +444,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 28,
+ "weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -497,7 +497,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 30,
+ "weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -566,7 +566,7 @@
},
"x-appwrite": {
"method": "updateMFA",
- "weight": 43,
+ "weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -619,7 +619,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -641,7 +641,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
- "weight": 45,
+ "weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -687,7 +687,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -709,7 +709,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
- "weight": 46,
+ "weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -773,7 +773,7 @@
]
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -790,7 +790,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 50,
+ "weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -838,7 +838,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"consumes": [
"application\/json"
@@ -860,7 +860,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
- "weight": 51,
+ "weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -917,7 +917,7 @@
]
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"consumes": [
"application\/json"
@@ -934,7 +934,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
- "weight": 52,
+ "weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -994,7 +994,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"consumes": [
"application\/json"
@@ -1016,7 +1016,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 44,
+ "weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1049,7 +1049,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1071,7 +1071,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 49,
+ "weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1102,7 +1102,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1124,7 +1124,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 47,
+ "weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1155,7 +1155,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1177,7 +1177,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 48,
+ "weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1232,7 +1232,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 31,
+ "weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1307,7 +1307,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 32,
+ "weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1388,7 +1388,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 34,
+ "weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1470,7 +1470,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 29,
+ "weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1523,7 +1523,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 35,
+ "weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1598,7 +1598,7 @@
},
"x-appwrite": {
"method": "createRecovery",
- "weight": 37,
+ "weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1681,7 +1681,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
- "weight": 38,
+ "weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1770,7 +1770,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 10,
+ "weight": 11,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1818,7 +1818,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 11,
+ "weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1873,7 +1873,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
- "weight": 16,
+ "weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1926,7 +1926,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
- "weight": 15,
+ "weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2006,7 +2006,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
- "weight": 25,
+ "weight": 26,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2083,7 +2083,7 @@
},
"x-appwrite": {
"method": "createOAuth2Session",
- "weight": 18,
+ "weight": 19,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2221,7 +2221,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
- "weight": 26,
+ "weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2301,7 +2301,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 17,
+ "weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2381,7 +2381,7 @@
},
"x-appwrite": {
"method": "getSession",
- "weight": 12,
+ "weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2444,7 +2444,7 @@
},
"x-appwrite": {
"method": "updateSession",
- "weight": 14,
+ "weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2502,7 +2502,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 13,
+ "weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2567,7 +2567,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 36,
+ "weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2622,7 +2622,7 @@
},
"x-appwrite": {
"method": "createPushTarget",
- "weight": 53,
+ "weight": 54,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2708,7 +2708,7 @@
},
"x-appwrite": {
"method": "updatePushTarget",
- "weight": 54,
+ "weight": 55,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2784,7 +2784,7 @@
},
"x-appwrite": {
"method": "deletePushTarget",
- "weight": 55,
+ "weight": 56,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2847,7 +2847,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
- "weight": 24,
+ "weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2933,7 +2933,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
- "weight": 23,
+ "weight": 24,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3025,7 +3025,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
- "weight": 22,
+ "weight": 23,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -3163,7 +3163,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
- "weight": 27,
+ "weight": 28,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3246,7 +3246,7 @@
},
"x-appwrite": {
"method": "createVerification",
- "weight": 39,
+ "weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3319,7 +3319,7 @@
},
"x-appwrite": {
"method": "updateVerification",
- "weight": 40,
+ "weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3401,7 +3401,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
- "weight": 41,
+ "weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3457,7 +3457,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 42,
+ "weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3539,7 +3539,7 @@
},
"x-appwrite": {
"method": "getBrowser",
- "weight": 59,
+ "weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3668,7 +3668,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
- "weight": 58,
+ "weight": 59,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3801,7 +3801,7 @@
},
"x-appwrite": {
"method": "getFavicon",
- "weight": 62,
+ "weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3868,7 +3868,7 @@
},
"x-appwrite": {
"method": "getFlag",
- "weight": 60,
+ "weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4359,7 +4359,7 @@
},
"x-appwrite": {
"method": "getImage",
- "weight": 61,
+ "weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4446,7 +4446,7 @@
},
"x-appwrite": {
"method": "getInitials",
- "weight": 64,
+ "weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4541,7 +4541,7 @@
},
"x-appwrite": {
"method": "getQR",
- "weight": 63,
+ "weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4636,7 +4636,7 @@
},
"x-appwrite": {
"method": "listDocuments",
- "weight": 108,
+ "weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4720,7 +4720,7 @@
},
"x-appwrite": {
"method": "createDocument",
- "weight": 107,
+ "weight": 108,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4828,7 +4828,7 @@
},
"x-appwrite": {
"method": "getDocument",
- "weight": 109,
+ "weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4920,7 +4920,7 @@
},
"x-appwrite": {
"method": "updateDocument",
- "weight": 111,
+ "weight": 112,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5019,7 +5019,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
- "weight": 112,
+ "weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5101,7 +5101,7 @@
},
"x-appwrite": {
"method": "listExecutions",
- "weight": 304,
+ "weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5167,7 +5167,7 @@
"summary": "Create execution",
"operationId": "functionsCreateExecution",
"consumes": [
- "multipart\/form-data"
+ "application\/json"
],
"produces": [
"multipart\/form-data"
@@ -5186,7 +5186,7 @@
},
"x-appwrite": {
"method": "createExecution",
- "weight": 303,
+ "weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5226,65 +5226,59 @@
"in": "path"
},
{
- "name": "body",
- "description": "HTTP body of execution. Default value is empty string.",
- "required": false,
- "type": "payload",
- "default": "",
- "in": "formData"
- },
- {
- "name": "async",
- "description": "Execute code in the background. Default value is false.",
- "required": false,
- "type": "boolean",
- "x-example": false,
- "default": false,
- "in": "formData"
- },
- {
- "name": "path",
- "description": "HTTP path of execution. Path can include query params. Default value is \/",
- "required": false,
- "type": "string",
- "x-example": "",
- "default": "\/",
- "in": "formData"
- },
- {
- "name": "method",
- "description": "HTTP method of execution. Default value is GET.",
- "required": false,
- "type": "string",
- "x-example": "GET",
- "enum": [
- "GET",
- "POST",
- "PUT",
- "PATCH",
- "DELETE",
- "OPTIONS"
- ],
- "x-enum-name": "ExecutionMethod",
- "x-enum-keys": [],
- "default": "POST",
- "in": "formData"
- },
- {
- "name": "headers",
- "description": "HTTP headers of execution. Defaults to empty.",
- "required": false,
- "type": "object",
- "default": [],
- "x-example": "{}",
- "in": "formData"
- },
- {
- "name": "scheduledAt",
- "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.",
- "required": false,
- "type": "string",
- "in": "formData"
+ "name": "payload",
+ "in": "body",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "description": "HTTP body of execution. Default value is empty string.",
+ "default": "",
+ "x-example": ""
+ },
+ "async": {
+ "type": "boolean",
+ "description": "Execute code in the background. Default value is false.",
+ "default": false,
+ "x-example": false
+ },
+ "path": {
+ "type": "string",
+ "description": "HTTP path of execution. Path can include query params. Default value is \/",
+ "default": "\/",
+ "x-example": ""
+ },
+ "method": {
+ "type": "string",
+ "description": "HTTP method of execution. Default value is GET.",
+ "default": "POST",
+ "x-example": "GET",
+ "enum": [
+ "GET",
+ "POST",
+ "PUT",
+ "PATCH",
+ "DELETE",
+ "OPTIONS"
+ ],
+ "x-enum-name": "ExecutionMethod",
+ "x-enum-keys": []
+ },
+ "headers": {
+ "type": "object",
+ "description": "HTTP headers of execution. Defaults to empty.",
+ "default": [],
+ "x-example": "{}"
+ },
+ "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.",
+ "default": null,
+ "x-example": null
+ }
+ }
+ }
}
]
}
@@ -5313,7 +5307,7 @@
},
"x-appwrite": {
"method": "getExecution",
- "weight": 305,
+ "weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5387,7 +5381,7 @@
},
"x-appwrite": {
"method": "query",
- "weight": 329,
+ "weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5463,7 +5457,7 @@
},
"x-appwrite": {
"method": "mutation",
- "weight": 328,
+ "weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5539,7 +5533,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 116,
+ "weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5573,7 +5567,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"consumes": [
"application\/json"
@@ -5595,7 +5589,7 @@
},
"x-appwrite": {
"method": "listCodes",
- "weight": 117,
+ "weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5651,7 +5645,7 @@
},
"x-appwrite": {
"method": "listContinents",
- "weight": 121,
+ "weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5707,7 +5701,7 @@
},
"x-appwrite": {
"method": "listCountries",
- "weight": 118,
+ "weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5763,7 +5757,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
- "weight": 119,
+ "weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5819,7 +5813,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
- "weight": 120,
+ "weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5875,7 +5869,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
- "weight": 122,
+ "weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5931,7 +5925,7 @@
},
"x-appwrite": {
"method": "listLanguages",
- "weight": 123,
+ "weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5987,7 +5981,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
- "weight": 380,
+ "weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6076,7 +6070,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
- "weight": 384,
+ "weight": 385,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6151,7 +6145,7 @@
},
"x-appwrite": {
"method": "listFiles",
- "weight": 206,
+ "weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6236,7 +6230,7 @@
},
"x-appwrite": {
"method": "createFile",
- "weight": 205,
+ "weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6330,7 +6324,7 @@
},
"x-appwrite": {
"method": "getFile",
- "weight": 207,
+ "weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6402,7 +6396,7 @@
},
"x-appwrite": {
"method": "updateFile",
- "weight": 212,
+ "weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6476,7 +6470,7 @@
]
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"consumes": [
"application\/json"
@@ -6493,7 +6487,7 @@
},
"x-appwrite": {
"method": "deleteFile",
- "weight": 213,
+ "weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6567,7 +6561,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
- "weight": 209,
+ "weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6641,7 +6635,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
- "weight": 208,
+ "weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6807,7 +6801,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -6841,7 +6836,7 @@
},
"x-appwrite": {
"method": "getFileView",
- "weight": 210,
+ "weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6915,7 +6910,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 217,
+ "weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6992,7 +6987,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 216,
+ "weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7086,7 +7081,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 218,
+ "weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7150,7 +7145,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 220,
+ "weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7227,7 +7222,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 222,
+ "weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7293,7 +7288,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 224,
+ "weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7378,7 +7373,7 @@
},
"x-appwrite": {
"method": "createMembership",
- "weight": 223,
+ "weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7495,7 +7490,7 @@
},
"x-appwrite": {
"method": "getMembership",
- "weight": 225,
+ "weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7567,7 +7562,7 @@
},
"x-appwrite": {
"method": "updateMembership",
- "weight": 226,
+ "weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7655,7 +7650,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
- "weight": 228,
+ "weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7729,7 +7724,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
- "weight": 227,
+ "weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7827,7 +7822,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 219,
+ "weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7890,7 +7885,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 221,
+ "weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9591,7 +9586,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/swagger2-1.6.x-console.json b/app/config/specs/swagger2-1.6.x-console.json
index 51935a5e01..ef651e4723 100644
--- a/app/config/specs/swagger2-1.6.x-console.json
+++ b/app/config/specs/swagger2-1.6.x-console.json
@@ -99,7 +99,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 8,
+ "weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -151,7 +151,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 7,
+ "weight": 8,
"cookies": false,
"type": "",
"deprecated": false,
@@ -237,7 +237,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 9,
+ "weight": 10,
"cookies": false,
"type": "",
"deprecated": false,
@@ -289,7 +289,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 33,
+ "weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -348,7 +348,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"consumes": [
"application\/json"
@@ -370,7 +370,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 56,
+ "weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -433,7 +433,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 57,
+ "weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -497,7 +497,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 28,
+ "weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -550,7 +550,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 30,
+ "weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -618,7 +618,7 @@
},
"x-appwrite": {
"method": "updateMFA",
- "weight": 43,
+ "weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -670,7 +670,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -692,7 +692,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
- "weight": 45,
+ "weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -737,7 +737,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -759,7 +759,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
- "weight": 46,
+ "weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -822,7 +822,7 @@
]
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -839,7 +839,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 50,
+ "weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -886,7 +886,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"consumes": [
"application\/json"
@@ -908,7 +908,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
- "weight": 51,
+ "weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -965,7 +965,7 @@
]
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"consumes": [
"application\/json"
@@ -982,7 +982,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
- "weight": 52,
+ "weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1041,7 +1041,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"consumes": [
"application\/json"
@@ -1063,7 +1063,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 44,
+ "weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1095,7 +1095,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1117,7 +1117,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 49,
+ "weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1147,7 +1147,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1169,7 +1169,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 47,
+ "weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1199,7 +1199,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1221,7 +1221,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 48,
+ "weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1275,7 +1275,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 31,
+ "weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1349,7 +1349,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 32,
+ "weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1429,7 +1429,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 34,
+ "weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1510,7 +1510,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 29,
+ "weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1562,7 +1562,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 35,
+ "weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1636,7 +1636,7 @@
},
"x-appwrite": {
"method": "createRecovery",
- "weight": 37,
+ "weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1718,7 +1718,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
- "weight": 38,
+ "weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1806,7 +1806,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 10,
+ "weight": 11,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1853,7 +1853,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 11,
+ "weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1907,7 +1907,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
- "weight": 16,
+ "weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1960,7 +1960,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
- "weight": 15,
+ "weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2040,7 +2040,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
- "weight": 25,
+ "weight": 26,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2117,7 +2117,7 @@
},
"x-appwrite": {
"method": "createOAuth2Session",
- "weight": 18,
+ "weight": 19,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2255,7 +2255,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
- "weight": 26,
+ "weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2335,7 +2335,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 17,
+ "weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2415,7 +2415,7 @@
},
"x-appwrite": {
"method": "getSession",
- "weight": 12,
+ "weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2477,7 +2477,7 @@
},
"x-appwrite": {
"method": "updateSession",
- "weight": 14,
+ "weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2534,7 +2534,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 13,
+ "weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2598,7 +2598,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 36,
+ "weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2652,7 +2652,7 @@
},
"x-appwrite": {
"method": "createPushTarget",
- "weight": 53,
+ "weight": 54,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2737,7 +2737,7 @@
},
"x-appwrite": {
"method": "updatePushTarget",
- "weight": 54,
+ "weight": 55,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2812,7 +2812,7 @@
},
"x-appwrite": {
"method": "deletePushTarget",
- "weight": 55,
+ "weight": 56,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2874,7 +2874,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
- "weight": 24,
+ "weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2960,7 +2960,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
- "weight": 23,
+ "weight": 24,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3052,7 +3052,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
- "weight": 22,
+ "weight": 23,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -3190,7 +3190,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
- "weight": 27,
+ "weight": 28,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3273,7 +3273,7 @@
},
"x-appwrite": {
"method": "createVerification",
- "weight": 39,
+ "weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3345,7 +3345,7 @@
},
"x-appwrite": {
"method": "updateVerification",
- "weight": 40,
+ "weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3426,7 +3426,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
- "weight": 41,
+ "weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3481,7 +3481,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 42,
+ "weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3562,7 +3562,7 @@
},
"x-appwrite": {
"method": "getBrowser",
- "weight": 59,
+ "weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3691,7 +3691,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
- "weight": 58,
+ "weight": 59,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3824,7 +3824,7 @@
},
"x-appwrite": {
"method": "getFavicon",
- "weight": 62,
+ "weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3891,7 +3891,7 @@
},
"x-appwrite": {
"method": "getFlag",
- "weight": 60,
+ "weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4382,7 +4382,7 @@
},
"x-appwrite": {
"method": "getImage",
- "weight": 61,
+ "weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4469,7 +4469,7 @@
},
"x-appwrite": {
"method": "getInitials",
- "weight": 64,
+ "weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4564,7 +4564,7 @@
},
"x-appwrite": {
"method": "getQR",
- "weight": 63,
+ "weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4637,7 +4637,7 @@
},
"\/console\/assistant": {
"post": {
- "summary": "Ask Query",
+ "summary": "Ask query",
"operationId": "assistantChat",
"consumes": [
"application\/json"
@@ -4659,7 +4659,7 @@
},
"x-appwrite": {
"method": "chat",
- "weight": 331,
+ "weight": 332,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4731,7 +4731,7 @@
},
"x-appwrite": {
"method": "variables",
- "weight": 330,
+ "weight": 331,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4783,7 +4783,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 69,
+ "weight": 70,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4857,7 +4857,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 68,
+ "weight": 69,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4943,7 +4943,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 113,
+ "weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5017,7 +5017,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 70,
+ "weight": 71,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5078,7 +5078,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 72,
+ "weight": 73,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5158,7 +5158,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 73,
+ "weight": 74,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5221,7 +5221,7 @@
},
"x-appwrite": {
"method": "listCollections",
- "weight": 75,
+ "weight": 76,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5303,7 +5303,7 @@
},
"x-appwrite": {
"method": "createCollection",
- "weight": 74,
+ "weight": 75,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5412,7 +5412,7 @@
},
"x-appwrite": {
"method": "getCollection",
- "weight": 76,
+ "weight": 77,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5481,7 +5481,7 @@
},
"x-appwrite": {
"method": "updateCollection",
- "weight": 78,
+ "weight": 79,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5584,7 +5584,7 @@
},
"x-appwrite": {
"method": "deleteCollection",
- "weight": 79,
+ "weight": 80,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5655,7 +5655,7 @@
},
"x-appwrite": {
"method": "listAttributes",
- "weight": 90,
+ "weight": 91,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5738,7 +5738,7 @@
},
"x-appwrite": {
"method": "createBooleanAttribute",
- "weight": 87,
+ "weight": 88,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5844,7 +5844,7 @@
},
"x-appwrite": {
"method": "updateBooleanAttribute",
- "weight": 99,
+ "weight": 100,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5954,7 +5954,7 @@
},
"x-appwrite": {
"method": "createDatetimeAttribute",
- "weight": 88,
+ "weight": 89,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6060,7 +6060,7 @@
},
"x-appwrite": {
"method": "updateDatetimeAttribute",
- "weight": 100,
+ "weight": 101,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6170,7 +6170,7 @@
},
"x-appwrite": {
"method": "createEmailAttribute",
- "weight": 81,
+ "weight": 82,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6276,7 +6276,7 @@
},
"x-appwrite": {
"method": "updateEmailAttribute",
- "weight": 93,
+ "weight": 94,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6386,7 +6386,7 @@
},
"x-appwrite": {
"method": "createEnumAttribute",
- "weight": 82,
+ "weight": 83,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6502,7 +6502,7 @@
},
"x-appwrite": {
"method": "updateEnumAttribute",
- "weight": 94,
+ "weight": 95,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6622,7 +6622,7 @@
},
"x-appwrite": {
"method": "createFloatAttribute",
- "weight": 86,
+ "weight": 87,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6740,7 +6740,7 @@
},
"x-appwrite": {
"method": "updateFloatAttribute",
- "weight": 98,
+ "weight": 99,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6864,7 +6864,7 @@
},
"x-appwrite": {
"method": "createIntegerAttribute",
- "weight": 85,
+ "weight": 86,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6982,7 +6982,7 @@
},
"x-appwrite": {
"method": "updateIntegerAttribute",
- "weight": 97,
+ "weight": 98,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7106,7 +7106,7 @@
},
"x-appwrite": {
"method": "createIpAttribute",
- "weight": 83,
+ "weight": 84,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7212,7 +7212,7 @@
},
"x-appwrite": {
"method": "updateIpAttribute",
- "weight": 95,
+ "weight": 96,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7322,7 +7322,7 @@
},
"x-appwrite": {
"method": "createRelationshipAttribute",
- "weight": 89,
+ "weight": 90,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7457,7 +7457,7 @@
},
"x-appwrite": {
"method": "createStringAttribute",
- "weight": 80,
+ "weight": 81,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7576,7 +7576,7 @@
},
"x-appwrite": {
"method": "updateStringAttribute",
- "weight": 92,
+ "weight": 93,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7692,7 +7692,7 @@
},
"x-appwrite": {
"method": "createUrlAttribute",
- "weight": 84,
+ "weight": 85,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7798,7 +7798,7 @@
},
"x-appwrite": {
"method": "updateUrlAttribute",
- "weight": 96,
+ "weight": 97,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7939,7 +7939,7 @@
},
"x-appwrite": {
"method": "getAttribute",
- "weight": 91,
+ "weight": 92,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8010,7 +8010,7 @@
},
"x-appwrite": {
"method": "deleteAttribute",
- "weight": 102,
+ "weight": 103,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8086,7 +8086,7 @@
},
"x-appwrite": {
"method": "updateRelationshipAttribute",
- "weight": 101,
+ "weight": 102,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8192,7 +8192,7 @@
},
"x-appwrite": {
"method": "listDocuments",
- "weight": 108,
+ "weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8276,7 +8276,7 @@
},
"x-appwrite": {
"method": "createDocument",
- "weight": 107,
+ "weight": 108,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8384,7 +8384,7 @@
},
"x-appwrite": {
"method": "getDocument",
- "weight": 109,
+ "weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8476,7 +8476,7 @@
},
"x-appwrite": {
"method": "updateDocument",
- "weight": 111,
+ "weight": 112,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8575,7 +8575,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
- "weight": 112,
+ "weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8657,7 +8657,7 @@
},
"x-appwrite": {
"method": "listDocumentLogs",
- "weight": 110,
+ "weight": 111,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8747,7 +8747,7 @@
},
"x-appwrite": {
"method": "listIndexes",
- "weight": 104,
+ "weight": 105,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8828,7 +8828,7 @@
},
"x-appwrite": {
"method": "createIndex",
- "weight": 103,
+ "weight": 104,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8950,7 +8950,7 @@
},
"x-appwrite": {
"method": "getIndex",
- "weight": 105,
+ "weight": 106,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9021,7 +9021,7 @@
},
"x-appwrite": {
"method": "deleteIndex",
- "weight": 106,
+ "weight": 107,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9099,7 +9099,7 @@
},
"x-appwrite": {
"method": "listCollectionLogs",
- "weight": 77,
+ "weight": 78,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9181,7 +9181,7 @@
},
"x-appwrite": {
"method": "getCollectionUsage",
- "weight": 115,
+ "weight": 116,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9271,7 +9271,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 71,
+ "weight": 72,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9345,7 +9345,7 @@
},
"x-appwrite": {
"method": "getDatabaseUsage",
- "weight": 114,
+ "weight": 115,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9427,7 +9427,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 287,
+ "weight": 288,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9501,7 +9501,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 286,
+ "weight": 287,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9559,6 +9559,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -9577,6 +9578,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -9584,23 +9587,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -9764,7 +9772,7 @@
},
"x-appwrite": {
"method": "listRuntimes",
- "weight": 288,
+ "weight": 289,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9817,7 +9825,7 @@
},
"x-appwrite": {
"method": "listSpecifications",
- "weight": 289,
+ "weight": 290,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9871,7 +9879,7 @@
},
"x-appwrite": {
"method": "listTemplates",
- "weight": 312,
+ "weight": 313,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9969,7 +9977,7 @@
},
"x-appwrite": {
"method": "getTemplate",
- "weight": 313,
+ "weight": 314,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10031,7 +10039,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 292,
+ "weight": 293,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10105,7 +10113,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 290,
+ "weight": 291,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10166,7 +10174,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 293,
+ "weight": 294,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10226,6 +10234,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -10244,6 +10253,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -10251,23 +10262,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -10399,7 +10415,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 296,
+ "weight": 297,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10462,7 +10478,7 @@
},
"x-appwrite": {
"method": "listDeployments",
- "weight": 298,
+ "weight": 299,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10544,7 +10560,7 @@
},
"x-appwrite": {
"method": "createDeployment",
- "weight": 297,
+ "weight": 298,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -10638,7 +10654,7 @@
},
"x-appwrite": {
"method": "getDeployment",
- "weight": 299,
+ "weight": 300,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10707,7 +10723,7 @@
},
"x-appwrite": {
"method": "updateDeployment",
- "weight": 295,
+ "weight": 296,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10771,7 +10787,7 @@
},
"x-appwrite": {
"method": "deleteDeployment",
- "weight": 300,
+ "weight": 301,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10837,7 +10853,7 @@
},
"x-appwrite": {
"method": "createBuild",
- "weight": 301,
+ "weight": 302,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10921,7 +10937,7 @@
},
"x-appwrite": {
"method": "updateDeploymentBuild",
- "weight": 302,
+ "weight": 303,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10992,7 +11008,7 @@
},
"x-appwrite": {
"method": "getDeploymentDownload",
- "weight": 294,
+ "weight": 295,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -11065,7 +11081,7 @@
},
"x-appwrite": {
"method": "listExecutions",
- "weight": 304,
+ "weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11131,7 +11147,7 @@
"summary": "Create execution",
"operationId": "functionsCreateExecution",
"consumes": [
- "multipart\/form-data"
+ "application\/json"
],
"produces": [
"multipart\/form-data"
@@ -11150,7 +11166,7 @@
},
"x-appwrite": {
"method": "createExecution",
- "weight": 303,
+ "weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11190,65 +11206,59 @@
"in": "path"
},
{
- "name": "body",
- "description": "HTTP body of execution. Default value is empty string.",
- "required": false,
- "type": "payload",
- "default": "",
- "in": "formData"
- },
- {
- "name": "async",
- "description": "Execute code in the background. Default value is false.",
- "required": false,
- "type": "boolean",
- "x-example": false,
- "default": false,
- "in": "formData"
- },
- {
- "name": "path",
- "description": "HTTP path of execution. Path can include query params. Default value is \/",
- "required": false,
- "type": "string",
- "x-example": "",
- "default": "\/",
- "in": "formData"
- },
- {
- "name": "method",
- "description": "HTTP method of execution. Default value is GET.",
- "required": false,
- "type": "string",
- "x-example": "GET",
- "enum": [
- "GET",
- "POST",
- "PUT",
- "PATCH",
- "DELETE",
- "OPTIONS"
- ],
- "x-enum-name": "ExecutionMethod",
- "x-enum-keys": [],
- "default": "POST",
- "in": "formData"
- },
- {
- "name": "headers",
- "description": "HTTP headers of execution. Defaults to empty.",
- "required": false,
- "type": "object",
- "default": [],
- "x-example": "{}",
- "in": "formData"
- },
- {
- "name": "scheduledAt",
- "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.",
- "required": false,
- "type": "string",
- "in": "formData"
+ "name": "payload",
+ "in": "body",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "description": "HTTP body of execution. Default value is empty string.",
+ "default": "",
+ "x-example": ""
+ },
+ "async": {
+ "type": "boolean",
+ "description": "Execute code in the background. Default value is false.",
+ "default": false,
+ "x-example": false
+ },
+ "path": {
+ "type": "string",
+ "description": "HTTP path of execution. Path can include query params. Default value is \/",
+ "default": "\/",
+ "x-example": ""
+ },
+ "method": {
+ "type": "string",
+ "description": "HTTP method of execution. Default value is GET.",
+ "default": "POST",
+ "x-example": "GET",
+ "enum": [
+ "GET",
+ "POST",
+ "PUT",
+ "PATCH",
+ "DELETE",
+ "OPTIONS"
+ ],
+ "x-enum-name": "ExecutionMethod",
+ "x-enum-keys": []
+ },
+ "headers": {
+ "type": "object",
+ "description": "HTTP headers of execution. Defaults to empty.",
+ "default": [],
+ "x-example": "{}"
+ },
+ "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.",
+ "default": null,
+ "x-example": null
+ }
+ }
+ }
}
]
}
@@ -11277,7 +11287,7 @@
},
"x-appwrite": {
"method": "getExecution",
- "weight": 305,
+ "weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11344,7 +11354,7 @@
},
"x-appwrite": {
"method": "deleteExecution",
- "weight": 306,
+ "weight": 307,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11415,7 +11425,7 @@
},
"x-appwrite": {
"method": "getFunctionUsage",
- "weight": 291,
+ "weight": 292,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11497,7 +11507,7 @@
},
"x-appwrite": {
"method": "listVariables",
- "weight": 308,
+ "weight": 309,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11558,7 +11568,7 @@
},
"x-appwrite": {
"method": "createVariable",
- "weight": 307,
+ "weight": 308,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11646,7 +11656,7 @@
},
"x-appwrite": {
"method": "getVariable",
- "weight": 309,
+ "weight": 310,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11715,7 +11725,7 @@
},
"x-appwrite": {
"method": "updateVariable",
- "weight": 310,
+ "weight": 311,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11803,7 +11813,7 @@
},
"x-appwrite": {
"method": "deleteVariable",
- "weight": 311,
+ "weight": 312,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11874,7 +11884,7 @@
},
"x-appwrite": {
"method": "query",
- "weight": 329,
+ "weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -11950,7 +11960,7 @@
},
"x-appwrite": {
"method": "mutation",
- "weight": 328,
+ "weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -12026,7 +12036,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 124,
+ "weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12079,7 +12089,7 @@
},
"x-appwrite": {
"method": "getAntivirus",
- "weight": 146,
+ "weight": 147,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12132,7 +12142,7 @@
},
"x-appwrite": {
"method": "getCache",
- "weight": 127,
+ "weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12185,7 +12195,7 @@
},
"x-appwrite": {
"method": "getCertificate",
- "weight": 133,
+ "weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12247,7 +12257,7 @@
},
"x-appwrite": {
"method": "getDB",
- "weight": 126,
+ "weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12300,7 +12310,7 @@
},
"x-appwrite": {
"method": "getPubSub",
- "weight": 129,
+ "weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12353,7 +12363,7 @@
},
"x-appwrite": {
"method": "getQueue",
- "weight": 128,
+ "weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12406,7 +12416,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
- "weight": 135,
+ "weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12470,7 +12480,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
- "weight": 134,
+ "weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12534,7 +12544,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
- "weight": 136,
+ "weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12607,7 +12617,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
- "weight": 137,
+ "weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12671,7 +12681,7 @@
},
"x-appwrite": {
"method": "getFailedJobs",
- "weight": 147,
+ "weight": 148,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12759,7 +12769,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
- "weight": 141,
+ "weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12823,7 +12833,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
- "weight": 132,
+ "weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12887,7 +12897,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
- "weight": 138,
+ "weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12951,7 +12961,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
- "weight": 139,
+ "weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13015,7 +13025,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
- "weight": 140,
+ "weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13079,7 +13089,7 @@
},
"x-appwrite": {
"method": "getQueueUsage",
- "weight": 142,
+ "weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13143,7 +13153,7 @@
},
"x-appwrite": {
"method": "getQueueUsageDump",
- "weight": 143,
+ "weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13207,7 +13217,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
- "weight": 131,
+ "weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13271,7 +13281,7 @@
},
"x-appwrite": {
"method": "getStorage",
- "weight": 145,
+ "weight": 146,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13324,7 +13334,7 @@
},
"x-appwrite": {
"method": "getStorageLocal",
- "weight": 144,
+ "weight": 145,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13377,7 +13387,7 @@
},
"x-appwrite": {
"method": "getTime",
- "weight": 130,
+ "weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13430,7 +13440,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 116,
+ "weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13464,7 +13474,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"consumes": [
"application\/json"
@@ -13486,7 +13496,7 @@
},
"x-appwrite": {
"method": "listCodes",
- "weight": 117,
+ "weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13542,7 +13552,7 @@
},
"x-appwrite": {
"method": "listContinents",
- "weight": 121,
+ "weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13598,7 +13608,7 @@
},
"x-appwrite": {
"method": "listCountries",
- "weight": 118,
+ "weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13654,7 +13664,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
- "weight": 119,
+ "weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13710,7 +13720,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
- "weight": 120,
+ "weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13766,7 +13776,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
- "weight": 122,
+ "weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13822,7 +13832,7 @@
},
"x-appwrite": {
"method": "listLanguages",
- "weight": 123,
+ "weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13878,7 +13888,7 @@
},
"x-appwrite": {
"method": "listMessages",
- "weight": 388,
+ "weight": 389,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13955,7 +13965,7 @@
},
"x-appwrite": {
"method": "createEmail",
- "weight": 385,
+ "weight": 386,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14115,7 +14125,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 392,
+ "weight": 393,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14272,7 +14282,7 @@
},
"x-appwrite": {
"method": "createPush",
- "weight": 387,
+ "weight": 388,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14447,7 +14457,7 @@
},
"x-appwrite": {
"method": "updatePush",
- "weight": 394,
+ "weight": 395,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14619,7 +14629,7 @@
},
"x-appwrite": {
"method": "createSms",
- "weight": 386,
+ "weight": 387,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14739,7 +14749,7 @@
},
"x-appwrite": {
"method": "updateSms",
- "weight": 393,
+ "weight": 394,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14857,7 +14867,7 @@
},
"x-appwrite": {
"method": "getMessage",
- "weight": 391,
+ "weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14916,7 +14926,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 395,
+ "weight": 396,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14980,7 +14990,7 @@
},
"x-appwrite": {
"method": "listMessageLogs",
- "weight": 389,
+ "weight": 390,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15056,7 +15066,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 390,
+ "weight": 391,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15132,7 +15142,7 @@
},
"x-appwrite": {
"method": "listProviders",
- "weight": 360,
+ "weight": 361,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15209,7 +15219,7 @@
},
"x-appwrite": {
"method": "createApnsProvider",
- "weight": 359,
+ "weight": 360,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15326,7 +15336,7 @@
},
"x-appwrite": {
"method": "updateApnsProvider",
- "weight": 372,
+ "weight": 373,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15441,7 +15451,7 @@
},
"x-appwrite": {
"method": "createFcmProvider",
- "weight": 358,
+ "weight": 359,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15534,7 +15544,7 @@
},
"x-appwrite": {
"method": "updateFcmProvider",
- "weight": 371,
+ "weight": 372,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15625,7 +15635,7 @@
},
"x-appwrite": {
"method": "createMailgunProvider",
- "weight": 350,
+ "weight": 351,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15754,7 +15764,7 @@
},
"x-appwrite": {
"method": "updateMailgunProvider",
- "weight": 363,
+ "weight": 364,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15881,7 +15891,7 @@
},
"x-appwrite": {
"method": "createMsg91Provider",
- "weight": 353,
+ "weight": 354,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15986,7 +15996,7 @@
},
"x-appwrite": {
"method": "updateMsg91Provider",
- "weight": 366,
+ "weight": 367,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16089,7 +16099,7 @@
},
"x-appwrite": {
"method": "createSendgridProvider",
- "weight": 351,
+ "weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16206,7 +16216,7 @@
},
"x-appwrite": {
"method": "updateSendgridProvider",
- "weight": 364,
+ "weight": 365,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16321,7 +16331,7 @@
},
"x-appwrite": {
"method": "createSmtpProvider",
- "weight": 352,
+ "weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16482,7 +16492,7 @@
},
"x-appwrite": {
"method": "updateSmtpProvider",
- "weight": 365,
+ "weight": 366,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16640,7 +16650,7 @@
},
"x-appwrite": {
"method": "createTelesignProvider",
- "weight": 354,
+ "weight": 355,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16745,7 +16755,7 @@
},
"x-appwrite": {
"method": "updateTelesignProvider",
- "weight": 367,
+ "weight": 368,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16848,7 +16858,7 @@
},
"x-appwrite": {
"method": "createTextmagicProvider",
- "weight": 355,
+ "weight": 356,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16953,7 +16963,7 @@
},
"x-appwrite": {
"method": "updateTextmagicProvider",
- "weight": 368,
+ "weight": 369,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17056,7 +17066,7 @@
},
"x-appwrite": {
"method": "createTwilioProvider",
- "weight": 356,
+ "weight": 357,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17161,7 +17171,7 @@
},
"x-appwrite": {
"method": "updateTwilioProvider",
- "weight": 369,
+ "weight": 370,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17264,7 +17274,7 @@
},
"x-appwrite": {
"method": "createVonageProvider",
- "weight": 357,
+ "weight": 358,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17369,7 +17379,7 @@
},
"x-appwrite": {
"method": "updateVonageProvider",
- "weight": 370,
+ "weight": 371,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17472,7 +17482,7 @@
},
"x-appwrite": {
"method": "getProvider",
- "weight": 362,
+ "weight": 363,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17531,7 +17541,7 @@
},
"x-appwrite": {
"method": "deleteProvider",
- "weight": 373,
+ "weight": 374,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17595,7 +17605,7 @@
},
"x-appwrite": {
"method": "listProviderLogs",
- "weight": 361,
+ "weight": 362,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17671,7 +17681,7 @@
},
"x-appwrite": {
"method": "listSubscriberLogs",
- "weight": 382,
+ "weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17747,7 +17757,7 @@
},
"x-appwrite": {
"method": "listTopics",
- "weight": 375,
+ "weight": 376,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17822,7 +17832,7 @@
},
"x-appwrite": {
"method": "createTopic",
- "weight": 374,
+ "weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17914,7 +17924,7 @@
},
"x-appwrite": {
"method": "getTopic",
- "weight": 377,
+ "weight": 378,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17976,7 +17986,7 @@
},
"x-appwrite": {
"method": "updateTopic",
- "weight": 378,
+ "weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18059,7 +18069,7 @@
},
"x-appwrite": {
"method": "deleteTopic",
- "weight": 379,
+ "weight": 380,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18123,7 +18133,7 @@
},
"x-appwrite": {
"method": "listTopicLogs",
- "weight": 376,
+ "weight": 377,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18199,7 +18209,7 @@
},
"x-appwrite": {
"method": "listSubscribers",
- "weight": 381,
+ "weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18282,7 +18292,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
- "weight": 380,
+ "weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18374,7 +18384,7 @@
},
"x-appwrite": {
"method": "getSubscriber",
- "weight": 383,
+ "weight": 384,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18441,7 +18451,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
- "weight": 384,
+ "weight": 385,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18494,7 +18504,7 @@
},
"\/migrations": {
"get": {
- "summary": "List Migrations",
+ "summary": "List migrations",
"operationId": "migrationsList",
"consumes": [
"application\/json"
@@ -18516,7 +18526,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 337,
+ "weight": 338,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18569,7 +18579,7 @@
},
"\/migrations\/appwrite": {
"post": {
- "summary": "Migrate Appwrite Data",
+ "summary": "Migrate Appwrite data",
"operationId": "migrationsCreateAppwriteMigration",
"consumes": [
"application\/json"
@@ -18591,7 +18601,7 @@
},
"x-appwrite": {
"method": "createAppwriteMigration",
- "weight": 332,
+ "weight": 333,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18665,7 +18675,7 @@
},
"\/migrations\/appwrite\/report": {
"get": {
- "summary": "Generate a report on Appwrite Data",
+ "summary": "Generate a report on Appwrite data",
"operationId": "migrationsGetAppwriteReport",
"consumes": [
"application\/json"
@@ -18687,7 +18697,7 @@
},
"x-appwrite": {
"method": "getAppwriteReport",
- "weight": 339,
+ "weight": 340,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18755,7 +18765,7 @@
},
"\/migrations\/firebase": {
"post": {
- "summary": "Migrate Firebase Data (Service Account)",
+ "summary": "Migrate Firebase data (Service Account)",
"operationId": "migrationsCreateFirebaseMigration",
"consumes": [
"application\/json"
@@ -18777,7 +18787,7 @@
},
"x-appwrite": {
"method": "createFirebaseMigration",
- "weight": 334,
+ "weight": 335,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18837,7 +18847,7 @@
},
"\/migrations\/firebase\/deauthorize": {
"get": {
- "summary": "Revoke Appwrite's authorization to access Firebase Projects",
+ "summary": "Revoke Appwrite's authorization to access Firebase projects",
"operationId": "migrationsDeleteFirebaseAuth",
"consumes": [
"application\/json"
@@ -18859,7 +18869,7 @@
},
"x-appwrite": {
"method": "deleteFirebaseAuth",
- "weight": 345,
+ "weight": 346,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18889,7 +18899,7 @@
},
"\/migrations\/firebase\/oauth": {
"post": {
- "summary": "Migrate Firebase Data (OAuth)",
+ "summary": "Migrate Firebase data (OAuth)",
"operationId": "migrationsCreateFirebaseOAuthMigration",
"consumes": [
"application\/json"
@@ -18911,7 +18921,7 @@
},
"x-appwrite": {
"method": "createFirebaseOAuthMigration",
- "weight": 333,
+ "weight": 334,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18971,7 +18981,7 @@
},
"\/migrations\/firebase\/projects": {
"get": {
- "summary": "List Firebase Projects",
+ "summary": "List Firebase projects",
"operationId": "migrationsListFirebaseProjects",
"consumes": [
"application\/json"
@@ -18993,7 +19003,7 @@
},
"x-appwrite": {
"method": "listFirebaseProjects",
- "weight": 344,
+ "weight": 345,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19023,7 +19033,7 @@
},
"\/migrations\/firebase\/report": {
"get": {
- "summary": "Generate a report on Firebase Data",
+ "summary": "Generate a report on Firebase data",
"operationId": "migrationsGetFirebaseReport",
"consumes": [
"application\/json"
@@ -19045,7 +19055,7 @@
},
"x-appwrite": {
"method": "getFirebaseReport",
- "weight": 340,
+ "weight": 341,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19096,7 +19106,7 @@
},
"\/migrations\/firebase\/report\/oauth": {
"get": {
- "summary": "Generate a report on Firebase Data using OAuth",
+ "summary": "Generate a report on Firebase data using OAuth",
"operationId": "migrationsGetFirebaseReportOAuth",
"consumes": [
"application\/json"
@@ -19118,7 +19128,7 @@
},
"x-appwrite": {
"method": "getFirebaseReportOAuth",
- "weight": 341,
+ "weight": 342,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19169,7 +19179,7 @@
},
"\/migrations\/nhost": {
"post": {
- "summary": "Migrate NHost Data",
+ "summary": "Migrate NHost data",
"operationId": "migrationsCreateNHostMigration",
"consumes": [
"application\/json"
@@ -19191,7 +19201,7 @@
},
"x-appwrite": {
"method": "createNHostMigration",
- "weight": 336,
+ "weight": 337,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19314,7 +19324,7 @@
},
"x-appwrite": {
"method": "getNHostReport",
- "weight": 347,
+ "weight": 348,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19414,7 +19424,7 @@
},
"\/migrations\/supabase": {
"post": {
- "summary": "Migrate Supabase Data",
+ "summary": "Migrate Supabase data",
"operationId": "migrationsCreateSupabaseMigration",
"consumes": [
"application\/json"
@@ -19436,7 +19446,7 @@
},
"x-appwrite": {
"method": "createSupabaseMigration",
- "weight": 335,
+ "weight": 336,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19552,7 +19562,7 @@
},
"x-appwrite": {
"method": "getSupabaseReport",
- "weight": 346,
+ "weight": 347,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19645,7 +19655,7 @@
},
"\/migrations\/{migrationId}": {
"get": {
- "summary": "Get Migration",
+ "summary": "Get migration",
"operationId": "migrationsGet",
"consumes": [
"application\/json"
@@ -19667,7 +19677,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 338,
+ "weight": 339,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19705,7 +19715,7 @@
]
},
"patch": {
- "summary": "Retry Migration",
+ "summary": "Retry migration",
"operationId": "migrationsRetry",
"consumes": [
"application\/json"
@@ -19727,7 +19737,7 @@
},
"x-appwrite": {
"method": "retry",
- "weight": 348,
+ "weight": 349,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19765,7 +19775,7 @@
]
},
"delete": {
- "summary": "Delete Migration",
+ "summary": "Delete migration",
"operationId": "migrationsDelete",
"consumes": [
"application\/json"
@@ -19782,7 +19792,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 349,
+ "weight": 350,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19844,7 +19854,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 194,
+ "weight": 195,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19908,7 +19918,7 @@
},
"\/project\/variables": {
"get": {
- "summary": "List Variables",
+ "summary": "List variables",
"operationId": "projectListVariables",
"consumes": [
"application\/json"
@@ -19930,7 +19940,7 @@
},
"x-appwrite": {
"method": "listVariables",
- "weight": 196,
+ "weight": 197,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19958,7 +19968,7 @@
]
},
"post": {
- "summary": "Create Variable",
+ "summary": "Create variable",
"operationId": "projectCreateVariable",
"consumes": [
"application\/json"
@@ -19980,7 +19990,7 @@
},
"x-appwrite": {
"method": "createVariable",
- "weight": 195,
+ "weight": 196,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20037,7 +20047,7 @@
},
"\/project\/variables\/{variableId}": {
"get": {
- "summary": "Get Variable",
+ "summary": "Get variable",
"operationId": "projectGetVariable",
"consumes": [
"application\/json"
@@ -20059,7 +20069,7 @@
},
"x-appwrite": {
"method": "getVariable",
- "weight": 197,
+ "weight": 198,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20097,7 +20107,7 @@
]
},
"put": {
- "summary": "Update Variable",
+ "summary": "Update variable",
"operationId": "projectUpdateVariable",
"consumes": [
"application\/json"
@@ -20119,7 +20129,7 @@
},
"x-appwrite": {
"method": "updateVariable",
- "weight": 198,
+ "weight": 199,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20181,7 +20191,7 @@
]
},
"delete": {
- "summary": "Delete Variable",
+ "summary": "Delete variable",
"operationId": "projectDeleteVariable",
"consumes": [
"application\/json"
@@ -20198,7 +20208,7 @@
},
"x-appwrite": {
"method": "deleteVariable",
- "weight": 199,
+ "weight": 200,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20260,7 +20270,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 150,
+ "weight": 151,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20333,7 +20343,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 149,
+ "weight": 150,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20485,7 +20495,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 151,
+ "weight": 152,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20545,7 +20555,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 152,
+ "weight": 153,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20672,7 +20682,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 168,
+ "weight": 169,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20734,7 +20744,7 @@
},
"x-appwrite": {
"method": "updateApiStatus",
- "weight": 156,
+ "weight": 157,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20828,7 +20838,7 @@
},
"x-appwrite": {
"method": "updateApiStatusAll",
- "weight": 157,
+ "weight": 158,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20908,7 +20918,7 @@
},
"x-appwrite": {
"method": "updateAuthDuration",
- "weight": 161,
+ "weight": 162,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20988,7 +20998,7 @@
},
"x-appwrite": {
"method": "updateAuthLimit",
- "weight": 160,
+ "weight": 161,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21068,7 +21078,7 @@
},
"x-appwrite": {
"method": "updateAuthSessionsLimit",
- "weight": 166,
+ "weight": 167,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21148,7 +21158,7 @@
},
"x-appwrite": {
"method": "updateMockNumbers",
- "weight": 167,
+ "weight": 168,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21231,7 +21241,7 @@
},
"x-appwrite": {
"method": "updateAuthPasswordDictionary",
- "weight": 164,
+ "weight": 165,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21311,7 +21321,7 @@
},
"x-appwrite": {
"method": "updateAuthPasswordHistory",
- "weight": 163,
+ "weight": 164,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21391,7 +21401,7 @@
},
"x-appwrite": {
"method": "updatePersonalDataCheck",
- "weight": 165,
+ "weight": 166,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21471,7 +21481,7 @@
},
"x-appwrite": {
"method": "updateSessionAlerts",
- "weight": 159,
+ "weight": 160,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21551,7 +21561,7 @@
},
"x-appwrite": {
"method": "updateAuthStatus",
- "weight": 162,
+ "weight": 163,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21650,7 +21660,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 180,
+ "weight": 181,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21739,7 +21749,7 @@
},
"x-appwrite": {
"method": "listKeys",
- "weight": 176,
+ "weight": 177,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21748,7 +21758,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21799,7 +21809,7 @@
},
"x-appwrite": {
"method": "createKey",
- "weight": 175,
+ "weight": 176,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21808,7 +21818,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21895,7 +21905,7 @@
},
"x-appwrite": {
"method": "getKey",
- "weight": 177,
+ "weight": 178,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21904,7 +21914,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21963,7 +21973,7 @@
},
"x-appwrite": {
"method": "updateKey",
- "weight": 178,
+ "weight": 179,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21972,7 +21982,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -22060,7 +22070,7 @@
},
"x-appwrite": {
"method": "deleteKey",
- "weight": 179,
+ "weight": 180,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22069,7 +22079,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -22130,7 +22140,7 @@
},
"x-appwrite": {
"method": "updateOAuth2",
- "weight": 158,
+ "weight": 159,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22271,7 +22281,7 @@
},
"x-appwrite": {
"method": "listPlatforms",
- "weight": 182,
+ "weight": 183,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22280,7 +22290,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -22331,7 +22341,7 @@
},
"x-appwrite": {
"method": "createPlatform",
- "weight": 181,
+ "weight": 182,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22340,7 +22350,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22455,7 +22465,7 @@
},
"x-appwrite": {
"method": "getPlatform",
- "weight": 183,
+ "weight": 184,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22464,7 +22474,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -22523,7 +22533,7 @@
},
"x-appwrite": {
"method": "updatePlatform",
- "weight": 184,
+ "weight": 185,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22532,7 +22542,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22622,7 +22632,7 @@
},
"x-appwrite": {
"method": "deletePlatform",
- "weight": 185,
+ "weight": 186,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22631,7 +22641,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22692,7 +22702,7 @@
},
"x-appwrite": {
"method": "updateServiceStatus",
- "weight": 154,
+ "weight": 155,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22794,7 +22804,7 @@
},
"x-appwrite": {
"method": "updateServiceStatusAll",
- "weight": 155,
+ "weight": 156,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22874,7 +22884,7 @@
},
"x-appwrite": {
"method": "updateSmtp",
- "weight": 186,
+ "weight": 187,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23003,7 +23013,7 @@
},
"x-appwrite": {
"method": "createSmtpTest",
- "weight": 187,
+ "weight": 188,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23101,7 +23111,8 @@
"default": "",
"x-example": "tls",
"enum": [
- "tls"
+ "tls",
+ "ssl"
],
"x-enum-name": "SMTPSecure",
"x-enum-keys": []
@@ -23142,7 +23153,7 @@
},
"x-appwrite": {
"method": "updateTeam",
- "weight": 153,
+ "weight": 154,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23222,7 +23233,7 @@
},
"x-appwrite": {
"method": "getEmailTemplate",
- "weight": 189,
+ "weight": 190,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23444,7 +23455,7 @@
},
"x-appwrite": {
"method": "updateEmailTemplate",
- "weight": 191,
+ "weight": 192,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23709,7 +23720,7 @@
},
"x-appwrite": {
"method": "deleteEmailTemplate",
- "weight": 193,
+ "weight": 194,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23933,7 +23944,7 @@
},
"x-appwrite": {
"method": "getSmsTemplate",
- "weight": 188,
+ "weight": 189,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24152,7 +24163,7 @@
},
"x-appwrite": {
"method": "updateSmsTemplate",
- "weight": 190,
+ "weight": 191,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24389,7 +24400,7 @@
},
"x-appwrite": {
"method": "deleteSmsTemplate",
- "weight": 192,
+ "weight": 193,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24610,7 +24621,7 @@
},
"x-appwrite": {
"method": "listWebhooks",
- "weight": 170,
+ "weight": 171,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24670,7 +24681,7 @@
},
"x-appwrite": {
"method": "createWebhook",
- "weight": 169,
+ "weight": 170,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24792,7 +24803,7 @@
},
"x-appwrite": {
"method": "getWebhook",
- "weight": 171,
+ "weight": 172,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24860,7 +24871,7 @@
},
"x-appwrite": {
"method": "updateWebhook",
- "weight": 172,
+ "weight": 173,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24983,7 +24994,7 @@
},
"x-appwrite": {
"method": "deleteWebhook",
- "weight": 174,
+ "weight": 175,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25053,7 +25064,7 @@
},
"x-appwrite": {
"method": "updateWebhookSignature",
- "weight": 173,
+ "weight": 174,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25101,7 +25112,7 @@
},
"\/proxy\/rules": {
"get": {
- "summary": "List Rules",
+ "summary": "List rules",
"operationId": "proxyListRules",
"consumes": [
"application\/json"
@@ -25123,7 +25134,7 @@
},
"x-appwrite": {
"method": "listRules",
- "weight": 315,
+ "weight": 316,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25174,7 +25185,7 @@
]
},
"post": {
- "summary": "Create Rule",
+ "summary": "Create rule",
"operationId": "proxyCreateRule",
"consumes": [
"application\/json"
@@ -25196,7 +25207,7 @@
},
"x-appwrite": {
"method": "createRule",
- "weight": 314,
+ "weight": 315,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25265,7 +25276,7 @@
},
"\/proxy\/rules\/{ruleId}": {
"get": {
- "summary": "Get Rule",
+ "summary": "Get rule",
"operationId": "proxyGetRule",
"consumes": [
"application\/json"
@@ -25287,7 +25298,7 @@
},
"x-appwrite": {
"method": "getRule",
- "weight": 316,
+ "weight": 317,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25325,7 +25336,7 @@
]
},
"delete": {
- "summary": "Delete Rule",
+ "summary": "Delete rule",
"operationId": "proxyDeleteRule",
"consumes": [
"application\/json"
@@ -25342,7 +25353,7 @@
},
"x-appwrite": {
"method": "deleteRule",
- "weight": 317,
+ "weight": 318,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25382,7 +25393,7 @@
},
"\/proxy\/rules\/{ruleId}\/verification": {
"patch": {
- "summary": "Update Rule Verification Status",
+ "summary": "Update rule verification status",
"operationId": "proxyUpdateRuleVerification",
"consumes": [
"application\/json"
@@ -25404,7 +25415,7 @@
},
"x-appwrite": {
"method": "updateRuleVerification",
- "weight": 318,
+ "weight": 319,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25466,7 +25477,7 @@
},
"x-appwrite": {
"method": "listBuckets",
- "weight": 201,
+ "weight": 202,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25540,7 +25551,7 @@
},
"x-appwrite": {
"method": "createBucket",
- "weight": 200,
+ "weight": 201,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25681,7 +25692,7 @@
},
"x-appwrite": {
"method": "getBucket",
- "weight": 202,
+ "weight": 203,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25742,7 +25753,7 @@
},
"x-appwrite": {
"method": "updateBucket",
- "weight": 203,
+ "weight": 204,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25877,7 +25888,7 @@
},
"x-appwrite": {
"method": "deleteBucket",
- "weight": 204,
+ "weight": 205,
"cookies": false,
"type": "",
"deprecated": false,
@@ -25940,7 +25951,7 @@
},
"x-appwrite": {
"method": "listFiles",
- "weight": 206,
+ "weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26025,7 +26036,7 @@
},
"x-appwrite": {
"method": "createFile",
- "weight": 205,
+ "weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -26119,7 +26130,7 @@
},
"x-appwrite": {
"method": "getFile",
- "weight": 207,
+ "weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26191,7 +26202,7 @@
},
"x-appwrite": {
"method": "updateFile",
- "weight": 212,
+ "weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26265,7 +26276,7 @@
]
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"consumes": [
"application\/json"
@@ -26282,7 +26293,7 @@
},
"x-appwrite": {
"method": "deleteFile",
- "weight": 213,
+ "weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26356,7 +26367,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
- "weight": 209,
+ "weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -26430,7 +26441,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
- "weight": 208,
+ "weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -26596,7 +26607,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -26630,7 +26642,7 @@
},
"x-appwrite": {
"method": "getFileView",
- "weight": 210,
+ "weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -26704,7 +26716,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 214,
+ "weight": 215,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26778,7 +26790,7 @@
},
"x-appwrite": {
"method": "getBucketUsage",
- "weight": 215,
+ "weight": 216,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26860,7 +26872,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 217,
+ "weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -26937,7 +26949,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 216,
+ "weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27031,7 +27043,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 218,
+ "weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27095,7 +27107,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 220,
+ "weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27172,7 +27184,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 222,
+ "weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27238,7 +27250,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 229,
+ "weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27312,7 +27324,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 224,
+ "weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27397,7 +27409,7 @@
},
"x-appwrite": {
"method": "createMembership",
- "weight": 223,
+ "weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27514,7 +27526,7 @@
},
"x-appwrite": {
"method": "getMembership",
- "weight": 225,
+ "weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27586,7 +27598,7 @@
},
"x-appwrite": {
"method": "updateMembership",
- "weight": 226,
+ "weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27674,7 +27686,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
- "weight": 228,
+ "weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27748,7 +27760,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
- "weight": 227,
+ "weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27845,7 +27857,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 219,
+ "weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27907,7 +27919,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 221,
+ "weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -27989,7 +28001,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 239,
+ "weight": 240,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28063,7 +28075,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 230,
+ "weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28160,7 +28172,7 @@
},
"x-appwrite": {
"method": "createArgon2User",
- "weight": 233,
+ "weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28253,7 +28265,7 @@
},
"x-appwrite": {
"method": "createBcryptUser",
- "weight": 231,
+ "weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28324,7 +28336,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"consumes": [
"application\/json"
@@ -28346,7 +28358,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 247,
+ "weight": 248,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28417,7 +28429,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 270,
+ "weight": 271,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28480,7 +28492,7 @@
},
"x-appwrite": {
"method": "createMD5User",
- "weight": 232,
+ "weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28573,7 +28585,7 @@
},
"x-appwrite": {
"method": "createPHPassUser",
- "weight": 235,
+ "weight": 236,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28666,7 +28678,7 @@
},
"x-appwrite": {
"method": "createScryptUser",
- "weight": 236,
+ "weight": 237,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28794,7 +28806,7 @@
},
"x-appwrite": {
"method": "createScryptModifiedUser",
- "weight": 237,
+ "weight": 238,
"cookies": false,
"type": "",
"deprecated": false,
@@ -28908,7 +28920,7 @@
},
"x-appwrite": {
"method": "createSHAUser",
- "weight": 234,
+ "weight": 235,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29022,7 +29034,7 @@
},
"x-appwrite": {
"method": "getUsage",
- "weight": 272,
+ "weight": 273,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29096,7 +29108,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 240,
+ "weight": 241,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29152,7 +29164,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 268,
+ "weight": 269,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29215,7 +29227,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 253,
+ "weight": 254,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29296,7 +29308,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 271,
+ "weight": 272,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29380,7 +29392,7 @@
},
"x-appwrite": {
"method": "updateLabels",
- "weight": 249,
+ "weight": 250,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29464,7 +29476,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 245,
+ "weight": 246,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29539,7 +29551,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 244,
+ "weight": 245,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29602,7 +29614,7 @@
},
"x-appwrite": {
"method": "updateMfa",
- "weight": 258,
+ "weight": 259,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29661,7 +29673,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -29683,7 +29695,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 263,
+ "weight": 264,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29737,7 +29749,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"consumes": [
"application\/json"
@@ -29759,7 +29771,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 259,
+ "weight": 260,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29800,7 +29812,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -29822,7 +29834,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 260,
+ "weight": 261,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29861,7 +29873,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -29883,7 +29895,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 262,
+ "weight": 263,
"cookies": false,
"type": "",
"deprecated": false,
@@ -29922,7 +29934,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -29944,7 +29956,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 261,
+ "weight": 262,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30007,7 +30019,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 251,
+ "weight": 252,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30088,7 +30100,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 252,
+ "weight": 253,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30169,7 +30181,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 254,
+ "weight": 255,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30250,7 +30262,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 241,
+ "weight": 242,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30311,7 +30323,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 256,
+ "weight": 257,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30392,7 +30404,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 243,
+ "weight": 244,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30453,7 +30465,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 264,
+ "weight": 265,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30509,7 +30521,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 267,
+ "weight": 268,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30567,7 +30579,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 266,
+ "weight": 267,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30638,7 +30650,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 248,
+ "weight": 249,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30697,7 +30709,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"consumes": [
"application\/json"
@@ -30719,7 +30731,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 246,
+ "weight": 247,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30771,7 +30783,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"consumes": [
"application\/json"
@@ -30793,7 +30805,7 @@
},
"x-appwrite": {
"method": "createTarget",
- "weight": 238,
+ "weight": 239,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30886,7 +30898,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"consumes": [
"application\/json"
@@ -30908,7 +30920,7 @@
},
"x-appwrite": {
"method": "getTarget",
- "weight": 242,
+ "weight": 243,
"cookies": false,
"type": "",
"deprecated": false,
@@ -30956,7 +30968,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"consumes": [
"application\/json"
@@ -30978,7 +30990,7 @@
},
"x-appwrite": {
"method": "updateTarget",
- "weight": 257,
+ "weight": 258,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31072,7 +31084,7 @@
},
"x-appwrite": {
"method": "deleteTarget",
- "weight": 269,
+ "weight": 270,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31144,7 +31156,7 @@
},
"x-appwrite": {
"method": "createToken",
- "weight": 265,
+ "weight": 266,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31228,7 +31240,7 @@
},
"x-appwrite": {
"method": "updateEmailVerification",
- "weight": 255,
+ "weight": 256,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31309,7 +31321,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 250,
+ "weight": 251,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31368,7 +31380,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories": {
"get": {
- "summary": "List Repositories",
+ "summary": "List repositories",
"operationId": "vcsListRepositories",
"consumes": [
"application\/json"
@@ -31390,7 +31402,7 @@
},
"x-appwrite": {
"method": "listRepositories",
- "weight": 277,
+ "weight": 278,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31459,7 +31471,7 @@
},
"x-appwrite": {
"method": "createRepository",
- "weight": 278,
+ "weight": 279,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31546,7 +31558,7 @@
},
"x-appwrite": {
"method": "getRepository",
- "weight": 279,
+ "weight": 280,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31594,7 +31606,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches": {
"get": {
- "summary": "List Repository Branches",
+ "summary": "List repository branches",
"operationId": "vcsListRepositoryBranches",
"consumes": [
"application\/json"
@@ -31616,7 +31628,7 @@
},
"x-appwrite": {
"method": "listRepositoryBranches",
- "weight": 280,
+ "weight": 281,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31686,7 +31698,7 @@
},
"x-appwrite": {
"method": "getRepositoryContents",
- "weight": 275,
+ "weight": 276,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31765,7 +31777,7 @@
},
"x-appwrite": {
"method": "createRepositoryDetection",
- "weight": 276,
+ "weight": 277,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31845,7 +31857,7 @@
},
"x-appwrite": {
"method": "updateExternalDeployments",
- "weight": 285,
+ "weight": 286,
"cookies": false,
"type": "",
"deprecated": false,
@@ -31933,7 +31945,7 @@
},
"x-appwrite": {
"method": "listInstallations",
- "weight": 282,
+ "weight": 283,
"cookies": false,
"type": "",
"deprecated": false,
@@ -32008,7 +32020,7 @@
},
"x-appwrite": {
"method": "getInstallation",
- "weight": 283,
+ "weight": 284,
"cookies": false,
"type": "",
"deprecated": false,
@@ -32046,7 +32058,7 @@
]
},
"delete": {
- "summary": "Delete Installation",
+ "summary": "Delete installation",
"operationId": "vcsDeleteInstallation",
"consumes": [
"application\/json"
@@ -32063,7 +32075,7 @@
},
"x-appwrite": {
"method": "deleteInstallation",
- "weight": 284,
+ "weight": 285,
"cookies": false,
"type": "",
"deprecated": false,
@@ -33456,6 +33468,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -33475,6 +33497,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -33513,6 +33537,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -33540,7 +33574,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -33578,6 +33614,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -33605,7 +33651,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -33643,6 +33691,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -33655,7 +33713,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -33693,6 +33753,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33711,6 +33781,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33749,6 +33821,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -33775,6 +33857,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -33814,6 +33898,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33832,6 +33926,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33870,6 +33966,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33888,6 +33994,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33926,6 +34034,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -33944,6 +34062,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33982,6 +34102,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -34019,6 +34149,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -34067,6 +34199,16 @@
},
"x-example": [],
"x-nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -34074,7 +34216,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -36106,7 +36250,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
@@ -36435,6 +36579,17 @@
"description": "SMTP server secure protocol",
"x-example": "tls"
},
+ "pingCount": {
+ "type": "integer",
+ "description": "Number of times the ping was received for this project.",
+ "x-example": 1,
+ "format": "int32"
+ },
+ "pingedAt": {
+ "type": "string",
+ "description": "Last ping datetime in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"authEmailPassword": {
"type": "boolean",
"description": "Email\/Password auth method status",
@@ -36562,6 +36717,8 @@
"smtpUsername",
"smtpPassword",
"smtpSecure",
+ "pingCount",
+ "pingedAt",
"authEmailPassword",
"authUsersAuthMagicURL",
"authEmailOtp",
@@ -37270,6 +37427,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total databases storage in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"databases": {
"type": "array",
"description": "Aggregated number of databases per period.",
@@ -37296,6 +37459,15 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "An array of the aggregated number of databases storage in bytes per period.",
+ "items": {
+ "type": "object",
+ "$ref": "#\/definitions\/metric"
+ },
+ "x-example": []
}
},
"required": [
@@ -37303,9 +37475,11 @@
"databasesTotal",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"databases",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageDatabase": {
@@ -37329,6 +37503,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total storage used in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"collections": {
"type": "array",
"description": "Aggregated number of collections per period.",
@@ -37346,14 +37526,25 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "Aggregated storage used in bytes per period.",
+ "items": {
+ "type": "object",
+ "$ref": "#\/definitions\/metric"
+ },
+ "x-example": []
}
},
"required": [
"range",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageCollection": {
@@ -37921,6 +38112,12 @@
"x-example": 0,
"format": "int32"
},
+ "databasesStorageTotal": {
+ "type": "integer",
+ "description": "Total aggregated sum of databases storage size (in bytes).",
+ "x-example": 0,
+ "format": "int32"
+ },
"usersTotal": {
"type": "integer",
"description": "Total aggregated number of users.",
@@ -38023,6 +38220,15 @@
},
"x-example": []
},
+ "databasesStorageBreakdown": {
+ "type": "array",
+ "description": "An array of the aggregated breakdown of storage usage by databases.",
+ "items": {
+ "type": "object",
+ "$ref": "#\/definitions\/metricBreakdown"
+ },
+ "x-example": []
+ },
"executionsMbSecondsBreakdown": {
"type": "array",
"description": "Aggregated breakdown in totals of execution mbSeconds by functions.",
@@ -38055,6 +38261,7 @@
"executionsTotal",
"documentsTotal",
"databasesTotal",
+ "databasesStorageTotal",
"usersTotal",
"filesStorageTotal",
"functionsStorageTotal",
@@ -38069,6 +38276,7 @@
"executions",
"executionsBreakdown",
"bucketsBreakdown",
+ "databasesStorageBreakdown",
"executionsMbSecondsBreakdown",
"buildsMbSecondsBreakdown",
"functionsStorageBreakdown"
@@ -38804,7 +39012,7 @@
},
"$createdAt": {
"type": "string",
- "description": "Variable creation date in ISO 8601 format.",
+ "description": "Migration creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"$updatedAt": {
diff --git a/app/config/specs/swagger2-1.6.x-server.json b/app/config/specs/swagger2-1.6.x-server.json
index af6274226f..37018916fa 100644
--- a/app/config/specs/swagger2-1.6.x-server.json
+++ b/app/config/specs/swagger2-1.6.x-server.json
@@ -102,7 +102,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 8,
+ "weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -156,7 +156,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 7,
+ "weight": 8,
"cookies": false,
"type": "",
"deprecated": false,
@@ -249,7 +249,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 33,
+ "weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -310,7 +310,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"consumes": [
"application\/json"
@@ -332,7 +332,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 56,
+ "weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -397,7 +397,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 57,
+ "weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -463,7 +463,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 28,
+ "weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -516,7 +516,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 30,
+ "weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -586,7 +586,7 @@
},
"x-appwrite": {
"method": "updateMFA",
- "weight": 43,
+ "weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -640,7 +640,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -662,7 +662,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
- "weight": 45,
+ "weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -709,7 +709,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -731,7 +731,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
- "weight": 46,
+ "weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -796,7 +796,7 @@
]
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -813,7 +813,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 50,
+ "weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -862,7 +862,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"consumes": [
"application\/json"
@@ -884,7 +884,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
- "weight": 51,
+ "weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -941,7 +941,7 @@
]
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"consumes": [
"application\/json"
@@ -958,7 +958,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
- "weight": 52,
+ "weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1019,7 +1019,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"consumes": [
"application\/json"
@@ -1041,7 +1041,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 44,
+ "weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1075,7 +1075,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1097,7 +1097,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 49,
+ "weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1129,7 +1129,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1151,7 +1151,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 47,
+ "weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1183,7 +1183,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1205,7 +1205,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 48,
+ "weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1261,7 +1261,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 31,
+ "weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1337,7 +1337,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 32,
+ "weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1419,7 +1419,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 34,
+ "weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1502,7 +1502,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 29,
+ "weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1556,7 +1556,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 35,
+ "weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1632,7 +1632,7 @@
},
"x-appwrite": {
"method": "createRecovery",
- "weight": 37,
+ "weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1716,7 +1716,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
- "weight": 38,
+ "weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1806,7 +1806,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 10,
+ "weight": 11,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1855,7 +1855,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 11,
+ "weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1911,7 +1911,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
- "weight": 16,
+ "weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1964,7 +1964,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
- "weight": 15,
+ "weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2044,7 +2044,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
- "weight": 25,
+ "weight": 26,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2124,7 +2124,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
- "weight": 26,
+ "weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2204,7 +2204,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 17,
+ "weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2284,7 +2284,7 @@
},
"x-appwrite": {
"method": "getSession",
- "weight": 12,
+ "weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2348,7 +2348,7 @@
},
"x-appwrite": {
"method": "updateSession",
- "weight": 14,
+ "weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2407,7 +2407,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 13,
+ "weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2473,7 +2473,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 36,
+ "weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2529,7 +2529,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
- "weight": 24,
+ "weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2615,7 +2615,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
- "weight": 23,
+ "weight": 24,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2707,7 +2707,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
- "weight": 22,
+ "weight": 23,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2845,7 +2845,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
- "weight": 27,
+ "weight": 28,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2928,7 +2928,7 @@
},
"x-appwrite": {
"method": "createVerification",
- "weight": 39,
+ "weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3002,7 +3002,7 @@
},
"x-appwrite": {
"method": "updateVerification",
- "weight": 40,
+ "weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3085,7 +3085,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
- "weight": 41,
+ "weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3142,7 +3142,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 42,
+ "weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3225,7 +3225,7 @@
},
"x-appwrite": {
"method": "getBrowser",
- "weight": 59,
+ "weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3356,7 +3356,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
- "weight": 58,
+ "weight": 59,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3491,7 +3491,7 @@
},
"x-appwrite": {
"method": "getFavicon",
- "weight": 62,
+ "weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3560,7 +3560,7 @@
},
"x-appwrite": {
"method": "getFlag",
- "weight": 60,
+ "weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4053,7 +4053,7 @@
},
"x-appwrite": {
"method": "getImage",
- "weight": 61,
+ "weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4142,7 +4142,7 @@
},
"x-appwrite": {
"method": "getInitials",
- "weight": 64,
+ "weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4239,7 +4239,7 @@
},
"x-appwrite": {
"method": "getQR",
- "weight": 63,
+ "weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4336,7 +4336,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 69,
+ "weight": 70,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4411,7 +4411,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 68,
+ "weight": 69,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4498,7 +4498,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 70,
+ "weight": 71,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4560,7 +4560,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 72,
+ "weight": 73,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4641,7 +4641,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 73,
+ "weight": 74,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4705,7 +4705,7 @@
},
"x-appwrite": {
"method": "listCollections",
- "weight": 75,
+ "weight": 76,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4788,7 +4788,7 @@
},
"x-appwrite": {
"method": "createCollection",
- "weight": 74,
+ "weight": 75,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4898,7 +4898,7 @@
},
"x-appwrite": {
"method": "getCollection",
- "weight": 76,
+ "weight": 77,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4968,7 +4968,7 @@
},
"x-appwrite": {
"method": "updateCollection",
- "weight": 78,
+ "weight": 79,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5072,7 +5072,7 @@
},
"x-appwrite": {
"method": "deleteCollection",
- "weight": 79,
+ "weight": 80,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5144,7 +5144,7 @@
},
"x-appwrite": {
"method": "listAttributes",
- "weight": 90,
+ "weight": 91,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5228,7 +5228,7 @@
},
"x-appwrite": {
"method": "createBooleanAttribute",
- "weight": 87,
+ "weight": 88,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5335,7 +5335,7 @@
},
"x-appwrite": {
"method": "updateBooleanAttribute",
- "weight": 99,
+ "weight": 100,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5446,7 +5446,7 @@
},
"x-appwrite": {
"method": "createDatetimeAttribute",
- "weight": 88,
+ "weight": 89,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5553,7 +5553,7 @@
},
"x-appwrite": {
"method": "updateDatetimeAttribute",
- "weight": 100,
+ "weight": 101,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5664,7 +5664,7 @@
},
"x-appwrite": {
"method": "createEmailAttribute",
- "weight": 81,
+ "weight": 82,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5771,7 +5771,7 @@
},
"x-appwrite": {
"method": "updateEmailAttribute",
- "weight": 93,
+ "weight": 94,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5882,7 +5882,7 @@
},
"x-appwrite": {
"method": "createEnumAttribute",
- "weight": 82,
+ "weight": 83,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5999,7 +5999,7 @@
},
"x-appwrite": {
"method": "updateEnumAttribute",
- "weight": 94,
+ "weight": 95,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6120,7 +6120,7 @@
},
"x-appwrite": {
"method": "createFloatAttribute",
- "weight": 86,
+ "weight": 87,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6239,7 +6239,7 @@
},
"x-appwrite": {
"method": "updateFloatAttribute",
- "weight": 98,
+ "weight": 99,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6364,7 +6364,7 @@
},
"x-appwrite": {
"method": "createIntegerAttribute",
- "weight": 85,
+ "weight": 86,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6483,7 +6483,7 @@
},
"x-appwrite": {
"method": "updateIntegerAttribute",
- "weight": 97,
+ "weight": 98,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6608,7 +6608,7 @@
},
"x-appwrite": {
"method": "createIpAttribute",
- "weight": 83,
+ "weight": 84,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6715,7 +6715,7 @@
},
"x-appwrite": {
"method": "updateIpAttribute",
- "weight": 95,
+ "weight": 96,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6826,7 +6826,7 @@
},
"x-appwrite": {
"method": "createRelationshipAttribute",
- "weight": 89,
+ "weight": 90,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6962,7 +6962,7 @@
},
"x-appwrite": {
"method": "createStringAttribute",
- "weight": 80,
+ "weight": 81,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7082,7 +7082,7 @@
},
"x-appwrite": {
"method": "updateStringAttribute",
- "weight": 92,
+ "weight": 93,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7199,7 +7199,7 @@
},
"x-appwrite": {
"method": "createUrlAttribute",
- "weight": 84,
+ "weight": 85,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7306,7 +7306,7 @@
},
"x-appwrite": {
"method": "updateUrlAttribute",
- "weight": 96,
+ "weight": 97,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7448,7 +7448,7 @@
},
"x-appwrite": {
"method": "getAttribute",
- "weight": 91,
+ "weight": 92,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7520,7 +7520,7 @@
},
"x-appwrite": {
"method": "deleteAttribute",
- "weight": 102,
+ "weight": 103,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7597,7 +7597,7 @@
},
"x-appwrite": {
"method": "updateRelationshipAttribute",
- "weight": 101,
+ "weight": 102,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7704,7 +7704,7 @@
},
"x-appwrite": {
"method": "listDocuments",
- "weight": 108,
+ "weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7790,7 +7790,7 @@
},
"x-appwrite": {
"method": "createDocument",
- "weight": 107,
+ "weight": 108,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7900,7 +7900,7 @@
},
"x-appwrite": {
"method": "getDocument",
- "weight": 109,
+ "weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7994,7 +7994,7 @@
},
"x-appwrite": {
"method": "updateDocument",
- "weight": 111,
+ "weight": 112,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8095,7 +8095,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
- "weight": 112,
+ "weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8179,7 +8179,7 @@
},
"x-appwrite": {
"method": "listIndexes",
- "weight": 104,
+ "weight": 105,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8261,7 +8261,7 @@
},
"x-appwrite": {
"method": "createIndex",
- "weight": 103,
+ "weight": 104,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8384,7 +8384,7 @@
},
"x-appwrite": {
"method": "getIndex",
- "weight": 105,
+ "weight": 106,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8456,7 +8456,7 @@
},
"x-appwrite": {
"method": "deleteIndex",
- "weight": 106,
+ "weight": 107,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8535,7 +8535,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 287,
+ "weight": 288,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8610,7 +8610,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 286,
+ "weight": 287,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8669,6 +8669,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -8687,6 +8688,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -8694,23 +8697,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -8874,7 +8882,7 @@
},
"x-appwrite": {
"method": "listRuntimes",
- "weight": 288,
+ "weight": 289,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8928,7 +8936,7 @@
},
"x-appwrite": {
"method": "listSpecifications",
- "weight": 289,
+ "weight": 290,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8983,7 +8991,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 290,
+ "weight": 291,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9045,7 +9053,7 @@
},
"x-appwrite": {
"method": "update",
- "weight": 293,
+ "weight": 294,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9106,6 +9114,7 @@
"node-19.0",
"node-20.0",
"node-21.0",
+ "node-22",
"php-8.0",
"php-8.1",
"php-8.2",
@@ -9124,6 +9133,8 @@
"deno-1.24",
"deno-1.35",
"deno-1.40",
+ "deno-1.46",
+ "deno-2.0",
"dart-2.15",
"dart-2.16",
"dart-2.17",
@@ -9131,23 +9142,28 @@
"dart-3.0",
"dart-3.1",
"dart-3.3",
- "dotnet-3.1",
+ "dart-3.5",
"dotnet-6.0",
"dotnet-7.0",
+ "dotnet-8.0",
"java-8.0",
"java-11.0",
"java-17.0",
"java-18.0",
"java-21.0",
+ "java-22",
"swift-5.5",
"swift-5.8",
"swift-5.9",
+ "swift-5.10",
"kotlin-1.6",
"kotlin-1.8",
"kotlin-1.9",
+ "kotlin-2.0",
"cpp-17",
"cpp-20",
"bun-1.0",
+ "bun-1.1",
"go-1.23"
],
"x-enum-name": null,
@@ -9279,7 +9295,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 296,
+ "weight": 297,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9343,7 +9359,7 @@
},
"x-appwrite": {
"method": "listDeployments",
- "weight": 298,
+ "weight": 299,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9426,7 +9442,7 @@
},
"x-appwrite": {
"method": "createDeployment",
- "weight": 297,
+ "weight": 298,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -9521,7 +9537,7 @@
},
"x-appwrite": {
"method": "getDeployment",
- "weight": 299,
+ "weight": 300,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9591,7 +9607,7 @@
},
"x-appwrite": {
"method": "updateDeployment",
- "weight": 295,
+ "weight": 296,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9656,7 +9672,7 @@
},
"x-appwrite": {
"method": "deleteDeployment",
- "weight": 300,
+ "weight": 301,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9723,7 +9739,7 @@
},
"x-appwrite": {
"method": "createBuild",
- "weight": 301,
+ "weight": 302,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9808,7 +9824,7 @@
},
"x-appwrite": {
"method": "updateDeploymentBuild",
- "weight": 302,
+ "weight": 303,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9880,7 +9896,7 @@
},
"x-appwrite": {
"method": "getDeploymentDownload",
- "weight": 294,
+ "weight": 295,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -9954,7 +9970,7 @@
},
"x-appwrite": {
"method": "listExecutions",
- "weight": 304,
+ "weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10022,7 +10038,7 @@
"summary": "Create execution",
"operationId": "functionsCreateExecution",
"consumes": [
- "multipart\/form-data"
+ "application\/json"
],
"produces": [
"multipart\/form-data"
@@ -10041,7 +10057,7 @@
},
"x-appwrite": {
"method": "createExecution",
- "weight": 303,
+ "weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10083,65 +10099,59 @@
"in": "path"
},
{
- "name": "body",
- "description": "HTTP body of execution. Default value is empty string.",
- "required": false,
- "type": "payload",
- "default": "",
- "in": "formData"
- },
- {
- "name": "async",
- "description": "Execute code in the background. Default value is false.",
- "required": false,
- "type": "boolean",
- "x-example": false,
- "default": false,
- "in": "formData"
- },
- {
- "name": "path",
- "description": "HTTP path of execution. Path can include query params. Default value is \/",
- "required": false,
- "type": "string",
- "x-example": "",
- "default": "\/",
- "in": "formData"
- },
- {
- "name": "method",
- "description": "HTTP method of execution. Default value is GET.",
- "required": false,
- "type": "string",
- "x-example": "GET",
- "enum": [
- "GET",
- "POST",
- "PUT",
- "PATCH",
- "DELETE",
- "OPTIONS"
- ],
- "x-enum-name": "ExecutionMethod",
- "x-enum-keys": [],
- "default": "POST",
- "in": "formData"
- },
- {
- "name": "headers",
- "description": "HTTP headers of execution. Defaults to empty.",
- "required": false,
- "type": "object",
- "default": [],
- "x-example": "{}",
- "in": "formData"
- },
- {
- "name": "scheduledAt",
- "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.",
- "required": false,
- "type": "string",
- "in": "formData"
+ "name": "payload",
+ "in": "body",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "description": "HTTP body of execution. Default value is empty string.",
+ "default": "",
+ "x-example": ""
+ },
+ "async": {
+ "type": "boolean",
+ "description": "Execute code in the background. Default value is false.",
+ "default": false,
+ "x-example": false
+ },
+ "path": {
+ "type": "string",
+ "description": "HTTP path of execution. Path can include query params. Default value is \/",
+ "default": "\/",
+ "x-example": ""
+ },
+ "method": {
+ "type": "string",
+ "description": "HTTP method of execution. Default value is GET.",
+ "default": "POST",
+ "x-example": "GET",
+ "enum": [
+ "GET",
+ "POST",
+ "PUT",
+ "PATCH",
+ "DELETE",
+ "OPTIONS"
+ ],
+ "x-enum-name": "ExecutionMethod",
+ "x-enum-keys": []
+ },
+ "headers": {
+ "type": "object",
+ "description": "HTTP headers of execution. Defaults to empty.",
+ "default": [],
+ "x-example": "{}"
+ },
+ "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.",
+ "default": null,
+ "x-example": null
+ }
+ }
+ }
}
]
}
@@ -10170,7 +10180,7 @@
},
"x-appwrite": {
"method": "getExecution",
- "weight": 305,
+ "weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10239,7 +10249,7 @@
},
"x-appwrite": {
"method": "deleteExecution",
- "weight": 306,
+ "weight": 307,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10311,7 +10321,7 @@
},
"x-appwrite": {
"method": "listVariables",
- "weight": 308,
+ "weight": 309,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10373,7 +10383,7 @@
},
"x-appwrite": {
"method": "createVariable",
- "weight": 307,
+ "weight": 308,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10462,7 +10472,7 @@
},
"x-appwrite": {
"method": "getVariable",
- "weight": 309,
+ "weight": 310,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10532,7 +10542,7 @@
},
"x-appwrite": {
"method": "updateVariable",
- "weight": 310,
+ "weight": 311,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10621,7 +10631,7 @@
},
"x-appwrite": {
"method": "deleteVariable",
- "weight": 311,
+ "weight": 312,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10693,7 +10703,7 @@
},
"x-appwrite": {
"method": "query",
- "weight": 329,
+ "weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -10771,7 +10781,7 @@
},
"x-appwrite": {
"method": "mutation",
- "weight": 328,
+ "weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -10849,7 +10859,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 124,
+ "weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10903,7 +10913,7 @@
},
"x-appwrite": {
"method": "getAntivirus",
- "weight": 146,
+ "weight": 147,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10957,7 +10967,7 @@
},
"x-appwrite": {
"method": "getCache",
- "weight": 127,
+ "weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11011,7 +11021,7 @@
},
"x-appwrite": {
"method": "getCertificate",
- "weight": 133,
+ "weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11074,7 +11084,7 @@
},
"x-appwrite": {
"method": "getDB",
- "weight": 126,
+ "weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11128,7 +11138,7 @@
},
"x-appwrite": {
"method": "getPubSub",
- "weight": 129,
+ "weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11182,7 +11192,7 @@
},
"x-appwrite": {
"method": "getQueue",
- "weight": 128,
+ "weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11236,7 +11246,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
- "weight": 135,
+ "weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11301,7 +11311,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
- "weight": 134,
+ "weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11366,7 +11376,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
- "weight": 136,
+ "weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11440,7 +11450,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
- "weight": 137,
+ "weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11505,7 +11515,7 @@
},
"x-appwrite": {
"method": "getFailedJobs",
- "weight": 147,
+ "weight": 148,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11594,7 +11604,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
- "weight": 141,
+ "weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11659,7 +11669,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
- "weight": 132,
+ "weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11724,7 +11734,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
- "weight": 138,
+ "weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11789,7 +11799,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
- "weight": 139,
+ "weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11854,7 +11864,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
- "weight": 140,
+ "weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11919,7 +11929,7 @@
},
"x-appwrite": {
"method": "getQueueUsage",
- "weight": 142,
+ "weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11984,7 +11994,7 @@
},
"x-appwrite": {
"method": "getQueueUsageDump",
- "weight": 143,
+ "weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12049,7 +12059,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
- "weight": 131,
+ "weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12114,7 +12124,7 @@
},
"x-appwrite": {
"method": "getStorage",
- "weight": 145,
+ "weight": 146,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12168,7 +12178,7 @@
},
"x-appwrite": {
"method": "getStorageLocal",
- "weight": 144,
+ "weight": 145,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12222,7 +12232,7 @@
},
"x-appwrite": {
"method": "getTime",
- "weight": 130,
+ "weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12276,7 +12286,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 116,
+ "weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12312,7 +12322,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"consumes": [
"application\/json"
@@ -12334,7 +12344,7 @@
},
"x-appwrite": {
"method": "listCodes",
- "weight": 117,
+ "weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12392,7 +12402,7 @@
},
"x-appwrite": {
"method": "listContinents",
- "weight": 121,
+ "weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12450,7 +12460,7 @@
},
"x-appwrite": {
"method": "listCountries",
- "weight": 118,
+ "weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12508,7 +12518,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
- "weight": 119,
+ "weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12566,7 +12576,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
- "weight": 120,
+ "weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12624,7 +12634,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
- "weight": 122,
+ "weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12682,7 +12692,7 @@
},
"x-appwrite": {
"method": "listLanguages",
- "weight": 123,
+ "weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12740,7 +12750,7 @@
},
"x-appwrite": {
"method": "listMessages",
- "weight": 388,
+ "weight": 389,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12818,7 +12828,7 @@
},
"x-appwrite": {
"method": "createEmail",
- "weight": 385,
+ "weight": 386,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12979,7 +12989,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 392,
+ "weight": 393,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13137,7 +13147,7 @@
},
"x-appwrite": {
"method": "createPush",
- "weight": 387,
+ "weight": 388,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13313,7 +13323,7 @@
},
"x-appwrite": {
"method": "updatePush",
- "weight": 394,
+ "weight": 395,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13486,7 +13496,7 @@
},
"x-appwrite": {
"method": "createSms",
- "weight": 386,
+ "weight": 387,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13607,7 +13617,7 @@
},
"x-appwrite": {
"method": "updateSms",
- "weight": 393,
+ "weight": 394,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13726,7 +13736,7 @@
},
"x-appwrite": {
"method": "getMessage",
- "weight": 391,
+ "weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13786,7 +13796,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 395,
+ "weight": 396,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13851,7 +13861,7 @@
},
"x-appwrite": {
"method": "listMessageLogs",
- "weight": 389,
+ "weight": 390,
"cookies": false,
"type": "",
"deprecated": false,
@@ -13928,7 +13938,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 390,
+ "weight": 391,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14005,7 +14015,7 @@
},
"x-appwrite": {
"method": "listProviders",
- "weight": 360,
+ "weight": 361,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14083,7 +14093,7 @@
},
"x-appwrite": {
"method": "createApnsProvider",
- "weight": 359,
+ "weight": 360,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14201,7 +14211,7 @@
},
"x-appwrite": {
"method": "updateApnsProvider",
- "weight": 372,
+ "weight": 373,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14317,7 +14327,7 @@
},
"x-appwrite": {
"method": "createFcmProvider",
- "weight": 358,
+ "weight": 359,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14411,7 +14421,7 @@
},
"x-appwrite": {
"method": "updateFcmProvider",
- "weight": 371,
+ "weight": 372,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14503,7 +14513,7 @@
},
"x-appwrite": {
"method": "createMailgunProvider",
- "weight": 350,
+ "weight": 351,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14633,7 +14643,7 @@
},
"x-appwrite": {
"method": "updateMailgunProvider",
- "weight": 363,
+ "weight": 364,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14761,7 +14771,7 @@
},
"x-appwrite": {
"method": "createMsg91Provider",
- "weight": 353,
+ "weight": 354,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14867,7 +14877,7 @@
},
"x-appwrite": {
"method": "updateMsg91Provider",
- "weight": 366,
+ "weight": 367,
"cookies": false,
"type": "",
"deprecated": false,
@@ -14971,7 +14981,7 @@
},
"x-appwrite": {
"method": "createSendgridProvider",
- "weight": 351,
+ "weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15089,7 +15099,7 @@
},
"x-appwrite": {
"method": "updateSendgridProvider",
- "weight": 364,
+ "weight": 365,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15205,7 +15215,7 @@
},
"x-appwrite": {
"method": "createSmtpProvider",
- "weight": 352,
+ "weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15367,7 +15377,7 @@
},
"x-appwrite": {
"method": "updateSmtpProvider",
- "weight": 365,
+ "weight": 366,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15526,7 +15536,7 @@
},
"x-appwrite": {
"method": "createTelesignProvider",
- "weight": 354,
+ "weight": 355,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15632,7 +15642,7 @@
},
"x-appwrite": {
"method": "updateTelesignProvider",
- "weight": 367,
+ "weight": 368,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15736,7 +15746,7 @@
},
"x-appwrite": {
"method": "createTextmagicProvider",
- "weight": 355,
+ "weight": 356,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15842,7 +15852,7 @@
},
"x-appwrite": {
"method": "updateTextmagicProvider",
- "weight": 368,
+ "weight": 369,
"cookies": false,
"type": "",
"deprecated": false,
@@ -15946,7 +15956,7 @@
},
"x-appwrite": {
"method": "createTwilioProvider",
- "weight": 356,
+ "weight": 357,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16052,7 +16062,7 @@
},
"x-appwrite": {
"method": "updateTwilioProvider",
- "weight": 369,
+ "weight": 370,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16156,7 +16166,7 @@
},
"x-appwrite": {
"method": "createVonageProvider",
- "weight": 357,
+ "weight": 358,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16262,7 +16272,7 @@
},
"x-appwrite": {
"method": "updateVonageProvider",
- "weight": 370,
+ "weight": 371,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16366,7 +16376,7 @@
},
"x-appwrite": {
"method": "getProvider",
- "weight": 362,
+ "weight": 363,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16426,7 +16436,7 @@
},
"x-appwrite": {
"method": "deleteProvider",
- "weight": 373,
+ "weight": 374,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16491,7 +16501,7 @@
},
"x-appwrite": {
"method": "listProviderLogs",
- "weight": 361,
+ "weight": 362,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16568,7 +16578,7 @@
},
"x-appwrite": {
"method": "listSubscriberLogs",
- "weight": 382,
+ "weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16645,7 +16655,7 @@
},
"x-appwrite": {
"method": "listTopics",
- "weight": 375,
+ "weight": 376,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16721,7 +16731,7 @@
},
"x-appwrite": {
"method": "createTopic",
- "weight": 374,
+ "weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16814,7 +16824,7 @@
},
"x-appwrite": {
"method": "getTopic",
- "weight": 377,
+ "weight": 378,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16877,7 +16887,7 @@
},
"x-appwrite": {
"method": "updateTopic",
- "weight": 378,
+ "weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -16961,7 +16971,7 @@
},
"x-appwrite": {
"method": "deleteTopic",
- "weight": 379,
+ "weight": 380,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17026,7 +17036,7 @@
},
"x-appwrite": {
"method": "listTopicLogs",
- "weight": 376,
+ "weight": 377,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17103,7 +17113,7 @@
},
"x-appwrite": {
"method": "listSubscribers",
- "weight": 381,
+ "weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17187,7 +17197,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
- "weight": 380,
+ "weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17281,7 +17291,7 @@
},
"x-appwrite": {
"method": "getSubscriber",
- "weight": 383,
+ "weight": 384,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17349,7 +17359,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
- "weight": 384,
+ "weight": 385,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17426,7 +17436,7 @@
},
"x-appwrite": {
"method": "listBuckets",
- "weight": 201,
+ "weight": 202,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17501,7 +17511,7 @@
},
"x-appwrite": {
"method": "createBucket",
- "weight": 200,
+ "weight": 201,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17643,7 +17653,7 @@
},
"x-appwrite": {
"method": "getBucket",
- "weight": 202,
+ "weight": 203,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17705,7 +17715,7 @@
},
"x-appwrite": {
"method": "updateBucket",
- "weight": 203,
+ "weight": 204,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17841,7 +17851,7 @@
},
"x-appwrite": {
"method": "deleteBucket",
- "weight": 204,
+ "weight": 205,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17905,7 +17915,7 @@
},
"x-appwrite": {
"method": "listFiles",
- "weight": 206,
+ "weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17992,7 +18002,7 @@
},
"x-appwrite": {
"method": "createFile",
- "weight": 205,
+ "weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -18088,7 +18098,7 @@
},
"x-appwrite": {
"method": "getFile",
- "weight": 207,
+ "weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18162,7 +18172,7 @@
},
"x-appwrite": {
"method": "updateFile",
- "weight": 212,
+ "weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18238,7 +18248,7 @@
]
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"consumes": [
"application\/json"
@@ -18255,7 +18265,7 @@
},
"x-appwrite": {
"method": "deleteFile",
- "weight": 213,
+ "weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18331,7 +18341,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
- "weight": 209,
+ "weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -18407,7 +18417,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
- "weight": 208,
+ "weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -18575,7 +18585,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -18609,7 +18620,7 @@
},
"x-appwrite": {
"method": "getFileView",
- "weight": 210,
+ "weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -18685,7 +18696,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 217,
+ "weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18764,7 +18775,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 216,
+ "weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18860,7 +18871,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 218,
+ "weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18926,7 +18937,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 220,
+ "weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19005,7 +19016,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 222,
+ "weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19073,7 +19084,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 224,
+ "weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19160,7 +19171,7 @@
},
"x-appwrite": {
"method": "createMembership",
- "weight": 223,
+ "weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19279,7 +19290,7 @@
},
"x-appwrite": {
"method": "getMembership",
- "weight": 225,
+ "weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19353,7 +19364,7 @@
},
"x-appwrite": {
"method": "updateMembership",
- "weight": 226,
+ "weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19443,7 +19454,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
- "weight": 228,
+ "weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19519,7 +19530,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
- "weight": 227,
+ "weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19618,7 +19629,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 219,
+ "weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19682,7 +19693,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 221,
+ "weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19766,7 +19777,7 @@
},
"x-appwrite": {
"method": "list",
- "weight": 239,
+ "weight": 240,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19841,7 +19852,7 @@
},
"x-appwrite": {
"method": "create",
- "weight": 230,
+ "weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -19939,7 +19950,7 @@
},
"x-appwrite": {
"method": "createArgon2User",
- "weight": 233,
+ "weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20033,7 +20044,7 @@
},
"x-appwrite": {
"method": "createBcryptUser",
- "weight": 231,
+ "weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20105,7 +20116,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"consumes": [
"application\/json"
@@ -20127,7 +20138,7 @@
},
"x-appwrite": {
"method": "listIdentities",
- "weight": 247,
+ "weight": 248,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20199,7 +20210,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
- "weight": 270,
+ "weight": 271,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20263,7 +20274,7 @@
},
"x-appwrite": {
"method": "createMD5User",
- "weight": 232,
+ "weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20357,7 +20368,7 @@
},
"x-appwrite": {
"method": "createPHPassUser",
- "weight": 235,
+ "weight": 236,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20451,7 +20462,7 @@
},
"x-appwrite": {
"method": "createScryptUser",
- "weight": 236,
+ "weight": 237,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20580,7 +20591,7 @@
},
"x-appwrite": {
"method": "createScryptModifiedUser",
- "weight": 237,
+ "weight": 238,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20695,7 +20706,7 @@
},
"x-appwrite": {
"method": "createSHAUser",
- "weight": 234,
+ "weight": 235,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20810,7 +20821,7 @@
},
"x-appwrite": {
"method": "get",
- "weight": 240,
+ "weight": 241,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20867,7 +20878,7 @@
},
"x-appwrite": {
"method": "delete",
- "weight": 268,
+ "weight": 269,
"cookies": false,
"type": "",
"deprecated": false,
@@ -20931,7 +20942,7 @@
},
"x-appwrite": {
"method": "updateEmail",
- "weight": 253,
+ "weight": 254,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21013,7 +21024,7 @@
},
"x-appwrite": {
"method": "createJWT",
- "weight": 271,
+ "weight": 272,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21098,7 +21109,7 @@
},
"x-appwrite": {
"method": "updateLabels",
- "weight": 249,
+ "weight": 250,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21183,7 +21194,7 @@
},
"x-appwrite": {
"method": "listLogs",
- "weight": 245,
+ "weight": 246,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21259,7 +21270,7 @@
},
"x-appwrite": {
"method": "listMemberships",
- "weight": 244,
+ "weight": 245,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21323,7 +21334,7 @@
},
"x-appwrite": {
"method": "updateMfa",
- "weight": 258,
+ "weight": 259,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21383,7 +21394,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -21405,7 +21416,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
- "weight": 263,
+ "weight": 264,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21460,7 +21471,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"consumes": [
"application\/json"
@@ -21482,7 +21493,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
- "weight": 259,
+ "weight": 260,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21524,7 +21535,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -21546,7 +21557,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
- "weight": 260,
+ "weight": 261,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21586,7 +21597,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -21608,7 +21619,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
- "weight": 262,
+ "weight": 263,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21648,7 +21659,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -21670,7 +21681,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
- "weight": 261,
+ "weight": 262,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21734,7 +21745,7 @@
},
"x-appwrite": {
"method": "updateName",
- "weight": 251,
+ "weight": 252,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21816,7 +21827,7 @@
},
"x-appwrite": {
"method": "updatePassword",
- "weight": 252,
+ "weight": 253,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21898,7 +21909,7 @@
},
"x-appwrite": {
"method": "updatePhone",
- "weight": 254,
+ "weight": 255,
"cookies": false,
"type": "",
"deprecated": false,
@@ -21980,7 +21991,7 @@
},
"x-appwrite": {
"method": "getPrefs",
- "weight": 241,
+ "weight": 242,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22042,7 +22053,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
- "weight": 256,
+ "weight": 257,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22124,7 +22135,7 @@
},
"x-appwrite": {
"method": "listSessions",
- "weight": 243,
+ "weight": 244,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22186,7 +22197,7 @@
},
"x-appwrite": {
"method": "createSession",
- "weight": 264,
+ "weight": 265,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22243,7 +22254,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
- "weight": 267,
+ "weight": 268,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22302,7 +22313,7 @@
},
"x-appwrite": {
"method": "deleteSession",
- "weight": 266,
+ "weight": 267,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22374,7 +22385,7 @@
},
"x-appwrite": {
"method": "updateStatus",
- "weight": 248,
+ "weight": 249,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22434,7 +22445,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"consumes": [
"application\/json"
@@ -22456,7 +22467,7 @@
},
"x-appwrite": {
"method": "listTargets",
- "weight": 246,
+ "weight": 247,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22509,7 +22520,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"consumes": [
"application\/json"
@@ -22531,7 +22542,7 @@
},
"x-appwrite": {
"method": "createTarget",
- "weight": 238,
+ "weight": 239,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22625,7 +22636,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"consumes": [
"application\/json"
@@ -22647,7 +22658,7 @@
},
"x-appwrite": {
"method": "getTarget",
- "weight": 242,
+ "weight": 243,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22696,7 +22707,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"consumes": [
"application\/json"
@@ -22718,7 +22729,7 @@
},
"x-appwrite": {
"method": "updateTarget",
- "weight": 257,
+ "weight": 258,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22813,7 +22824,7 @@
},
"x-appwrite": {
"method": "deleteTarget",
- "weight": 269,
+ "weight": 270,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22886,7 +22897,7 @@
},
"x-appwrite": {
"method": "createToken",
- "weight": 265,
+ "weight": 266,
"cookies": false,
"type": "",
"deprecated": false,
@@ -22971,7 +22982,7 @@
},
"x-appwrite": {
"method": "updateEmailVerification",
- "weight": 255,
+ "weight": 256,
"cookies": false,
"type": "",
"deprecated": false,
@@ -23053,7 +23064,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
- "weight": 250,
+ "weight": 251,
"cookies": false,
"type": "",
"deprecated": false,
@@ -24166,6 +24177,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -24185,6 +24206,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -24223,6 +24246,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -24250,7 +24283,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -24288,6 +24323,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -24315,7 +24360,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -24353,6 +24400,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -24365,7 +24422,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -24403,6 +24462,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24421,6 +24490,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24459,6 +24530,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -24485,6 +24566,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -24524,6 +24607,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24542,6 +24635,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24580,6 +24675,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24598,6 +24703,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24636,6 +24743,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -24654,6 +24771,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24692,6 +24811,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -24729,6 +24858,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -24777,6 +24908,16 @@
},
"x-example": [],
"x-nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -24784,7 +24925,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -26460,7 +26603,7 @@
"responseBody": {
"type": "string",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json
index ce9ea857bb..fce6a871a3 100644
--- a/app/config/specs/swagger2-latest-client.json
+++ b/app/config/specs/swagger2-latest-client.json
@@ -222,7 +222,7 @@
"tags": [
"account"
],
- "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\n",
+ "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\r\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\r\n",
"responses": {
"200": {
"description": "User",
@@ -293,7 +293,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"consumes": [
"application\/json"
@@ -619,7 +619,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -687,7 +687,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -773,7 +773,7 @@
]
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -838,7 +838,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"consumes": [
"application\/json"
@@ -917,7 +917,7 @@
]
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"consumes": [
"application\/json"
@@ -994,7 +994,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"consumes": [
"application\/json"
@@ -1049,7 +1049,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1102,7 +1102,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1155,7 +1155,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1670,7 +1670,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
+ "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
"responses": {
"200": {
"description": "Token",
@@ -1915,7 +1915,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Session",
@@ -2075,7 +2075,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\n\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\r\n\r\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"301": {
"description": "No content"
@@ -2836,7 +2836,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2922,7 +2922,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3017,7 +3017,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \n\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \r\n\r\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"301": {
"description": "No content"
@@ -3152,7 +3152,7 @@
"tags": [
"account"
],
- "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -3235,7 +3235,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\n",
+ "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3528,7 +3528,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
+ "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
"responses": {
"200": {
"description": "Image",
@@ -3657,7 +3657,7 @@
"tags": [
"avatars"
],
- "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -3790,7 +3790,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image",
@@ -3857,7 +3857,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4348,7 +4348,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image",
@@ -4435,7 +4435,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\n\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\r\n\r\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4530,7 +4530,7 @@
"tags": [
"avatars"
],
- "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\n",
+ "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -5528,7 +5528,7 @@
"tags": [
"locale"
],
- "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\n\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
+ "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\r\n\r\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
"responses": {
"200": {
"description": "Locale",
@@ -5573,7 +5573,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"consumes": [
"application\/json"
@@ -6225,7 +6225,7 @@
"tags": [
"storage"
],
- "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\n\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\n\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\n\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\n",
+ "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\r\n\r\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\r\n\r\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\r\n\r\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\r\n",
"responses": {
"201": {
"description": "File",
@@ -6476,7 +6476,7 @@
]
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"consumes": [
"application\/json"
@@ -6807,7 +6807,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -7367,7 +7368,7 @@
"tags": [
"teams"
],
- "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\n\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\n\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \n\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\n",
+ "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\r\n\r\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\r\n\r\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \r\n\r\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\r\n",
"responses": {
"201": {
"description": "Membership",
@@ -7556,7 +7557,7 @@
"tags": [
"teams"
],
- "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\n",
+ "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -7718,7 +7719,7 @@
"tags": [
"teams"
],
- "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\n\nIf the request is successful, a session for the user is automatically created.\n",
+ "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\r\n\r\nIf the request is successful, a session for the user is automatically created.\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -9589,9 +9590,9 @@
"format": "int32"
},
"responseBody": {
- "type": "string",
+ "type": "payload",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json
index 51935a5e01..9200c80593 100644
--- a/app/config/specs/swagger2-latest-console.json
+++ b/app/config/specs/swagger2-latest-console.json
@@ -278,7 +278,7 @@
"tags": [
"account"
],
- "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\n",
+ "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\r\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\r\n",
"responses": {
"200": {
"description": "User",
@@ -348,7 +348,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"consumes": [
"application\/json"
@@ -670,7 +670,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -737,7 +737,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -822,7 +822,7 @@
]
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -886,7 +886,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"consumes": [
"application\/json"
@@ -965,7 +965,7 @@
]
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"consumes": [
"application\/json"
@@ -1041,7 +1041,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"consumes": [
"application\/json"
@@ -1095,7 +1095,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1147,7 +1147,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1199,7 +1199,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1707,7 +1707,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
+ "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
"responses": {
"200": {
"description": "Token",
@@ -1949,7 +1949,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Session",
@@ -2109,7 +2109,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\n\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.\r\n\r\nIf there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"301": {
"description": "No content"
@@ -2863,7 +2863,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2949,7 +2949,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3044,7 +3044,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \n\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \r\n\r\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"301": {
"description": "No content"
@@ -3179,7 +3179,7 @@
"tags": [
"account"
],
- "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -3262,7 +3262,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\n",
+ "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3551,7 +3551,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
+ "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
"responses": {
"200": {
"description": "Image",
@@ -3680,7 +3680,7 @@
"tags": [
"avatars"
],
- "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -3813,7 +3813,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image",
@@ -3880,7 +3880,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4371,7 +4371,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image",
@@ -4458,7 +4458,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\n\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\r\n\r\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4553,7 +4553,7 @@
"tags": [
"avatars"
],
- "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\n",
+ "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4637,7 +4637,7 @@
},
"\/console\/assistant": {
"post": {
- "summary": "Ask Query",
+ "summary": "Ask query",
"operationId": "assistantChat",
"consumes": [
"application\/json"
@@ -4846,7 +4846,7 @@
"tags": [
"databases"
],
- "description": "Create a new Database.\n",
+ "description": "Create a new Database.\r\n",
"responses": {
"201": {
"description": "Database",
@@ -5727,7 +5727,7 @@
"tags": [
"databases"
],
- "description": "Create a boolean attribute.\n",
+ "description": "Create a boolean attribute.\r\n",
"responses": {
"202": {
"description": "AttributeBoolean",
@@ -6159,7 +6159,7 @@
"tags": [
"databases"
],
- "description": "Create an email attribute.\n",
+ "description": "Create an email attribute.\r\n",
"responses": {
"202": {
"description": "AttributeEmail",
@@ -6265,7 +6265,7 @@
"tags": [
"databases"
],
- "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEmail",
@@ -6375,7 +6375,7 @@
"tags": [
"databases"
],
- "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \n",
+ "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \r\n",
"responses": {
"202": {
"description": "AttributeEnum",
@@ -6491,7 +6491,7 @@
"tags": [
"databases"
],
- "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEnum",
@@ -6611,7 +6611,7 @@
"tags": [
"databases"
],
- "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeFloat",
@@ -6729,7 +6729,7 @@
"tags": [
"databases"
],
- "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeFloat",
@@ -6853,7 +6853,7 @@
"tags": [
"databases"
],
- "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeInteger",
@@ -6971,7 +6971,7 @@
"tags": [
"databases"
],
- "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeInteger",
@@ -7095,7 +7095,7 @@
"tags": [
"databases"
],
- "description": "Create IP address attribute.\n",
+ "description": "Create IP address attribute.\r\n",
"responses": {
"202": {
"description": "AttributeIP",
@@ -7201,7 +7201,7 @@
"tags": [
"databases"
],
- "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeIP",
@@ -7311,7 +7311,7 @@
"tags": [
"databases"
],
- "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"202": {
"description": "AttributeRelationship",
@@ -7446,7 +7446,7 @@
"tags": [
"databases"
],
- "description": "Create a string attribute.\n",
+ "description": "Create a string attribute.\r\n",
"responses": {
"202": {
"description": "AttributeString",
@@ -7565,7 +7565,7 @@
"tags": [
"databases"
],
- "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeString",
@@ -7681,7 +7681,7 @@
"tags": [
"databases"
],
- "description": "Create a URL attribute.\n",
+ "description": "Create a URL attribute.\r\n",
"responses": {
"202": {
"description": "AttributeURL",
@@ -7787,7 +7787,7 @@
"tags": [
"databases"
],
- "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeURL",
@@ -8075,7 +8075,7 @@
"tags": [
"databases"
],
- "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"200": {
"description": "AttributeRelationship",
@@ -8817,7 +8817,7 @@
"tags": [
"databases"
],
- "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\nAttributes can be `key`, `fulltext`, and `unique`.",
+ "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\r\nAttributes can be `key`, `fulltext`, and `unique`.",
"responses": {
"202": {
"description": "Index",
@@ -9806,7 +9806,7 @@
"tags": [
"functions"
],
- "description": "List allowed function specifications for this instance.\n",
+ "description": "List allowed function specifications for this instance.\r\n",
"responses": {
"200": {
"description": "Specifications List",
@@ -10533,7 +10533,7 @@
"tags": [
"functions"
],
- "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\n\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.",
+ "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\r\n\r\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\r\n\r\nUse the \"command\" param to set the entrypoint used to execute your code.",
"responses": {
"202": {
"description": "Deployment",
@@ -11336,7 +11336,7 @@
"tags": [
"functions"
],
- "description": "Delete a function execution by its unique ID.\n",
+ "description": "Delete a function execution by its unique ID.\r\n",
"responses": {
"204": {
"description": "No content"
@@ -12660,7 +12660,7 @@
"tags": [
"health"
],
- "description": "Returns the amount of failed jobs in a given queue.\n",
+ "description": "Returns the amount of failed jobs in a given queue.\r\n",
"responses": {
"200": {
"description": "Health Queue",
@@ -13419,7 +13419,7 @@
"tags": [
"locale"
],
- "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\n\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
+ "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\r\n\r\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
"responses": {
"200": {
"description": "Locale",
@@ -13464,7 +13464,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"consumes": [
"application\/json"
@@ -14104,7 +14104,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -14436,7 +14436,7 @@
"tags": [
"messaging"
],
- "description": "Update a push notification by its unique ID.\n",
+ "description": "Update a push notification by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -14728,7 +14728,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -14846,7 +14846,7 @@
"tags": [
"messaging"
],
- "description": "Get a message by its unique ID.\n",
+ "description": "Get a message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -17461,7 +17461,7 @@
"tags": [
"messaging"
],
- "description": "Get a provider by its unique ID.\n",
+ "description": "Get a provider by its unique ID.\r\n",
"responses": {
"200": {
"description": "Provider",
@@ -17903,7 +17903,7 @@
"tags": [
"messaging"
],
- "description": "Get a topic by its unique ID.\n",
+ "description": "Get a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -17965,7 +17965,7 @@
"tags": [
"messaging"
],
- "description": "Update a topic by its unique ID.\n",
+ "description": "Update a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -18363,7 +18363,7 @@
"tags": [
"messaging"
],
- "description": "Get a subscriber by its unique ID.\n",
+ "description": "Get a subscriber by its unique ID.\r\n",
"responses": {
"200": {
"description": "Subscriber",
@@ -18494,7 +18494,7 @@
},
"\/migrations": {
"get": {
- "summary": "List Migrations",
+ "summary": "List migrations",
"operationId": "migrationsList",
"consumes": [
"application\/json"
@@ -18569,7 +18569,7 @@
},
"\/migrations\/appwrite": {
"post": {
- "summary": "Migrate Appwrite Data",
+ "summary": "Migrate Appwrite data",
"operationId": "migrationsCreateAppwriteMigration",
"consumes": [
"application\/json"
@@ -18665,7 +18665,7 @@
},
"\/migrations\/appwrite\/report": {
"get": {
- "summary": "Generate a report on Appwrite Data",
+ "summary": "Generate a report on Appwrite data",
"operationId": "migrationsGetAppwriteReport",
"consumes": [
"application\/json"
@@ -18755,7 +18755,7 @@
},
"\/migrations\/firebase": {
"post": {
- "summary": "Migrate Firebase Data (Service Account)",
+ "summary": "Migrate Firebase data (Service Account)",
"operationId": "migrationsCreateFirebaseMigration",
"consumes": [
"application\/json"
@@ -18837,7 +18837,7 @@
},
"\/migrations\/firebase\/deauthorize": {
"get": {
- "summary": "Revoke Appwrite's authorization to access Firebase Projects",
+ "summary": "Revoke Appwrite's authorization to access Firebase projects",
"operationId": "migrationsDeleteFirebaseAuth",
"consumes": [
"application\/json"
@@ -18889,7 +18889,7 @@
},
"\/migrations\/firebase\/oauth": {
"post": {
- "summary": "Migrate Firebase Data (OAuth)",
+ "summary": "Migrate Firebase data (OAuth)",
"operationId": "migrationsCreateFirebaseOAuthMigration",
"consumes": [
"application\/json"
@@ -18971,7 +18971,7 @@
},
"\/migrations\/firebase\/projects": {
"get": {
- "summary": "List Firebase Projects",
+ "summary": "List Firebase projects",
"operationId": "migrationsListFirebaseProjects",
"consumes": [
"application\/json"
@@ -19023,7 +19023,7 @@
},
"\/migrations\/firebase\/report": {
"get": {
- "summary": "Generate a report on Firebase Data",
+ "summary": "Generate a report on Firebase data",
"operationId": "migrationsGetFirebaseReport",
"consumes": [
"application\/json"
@@ -19096,7 +19096,7 @@
},
"\/migrations\/firebase\/report\/oauth": {
"get": {
- "summary": "Generate a report on Firebase Data using OAuth",
+ "summary": "Generate a report on Firebase data using OAuth",
"operationId": "migrationsGetFirebaseReportOAuth",
"consumes": [
"application\/json"
@@ -19169,7 +19169,7 @@
},
"\/migrations\/nhost": {
"post": {
- "summary": "Migrate NHost Data",
+ "summary": "Migrate NHost data",
"operationId": "migrationsCreateNHostMigration",
"consumes": [
"application\/json"
@@ -19414,7 +19414,7 @@
},
"\/migrations\/supabase": {
"post": {
- "summary": "Migrate Supabase Data",
+ "summary": "Migrate Supabase data",
"operationId": "migrationsCreateSupabaseMigration",
"consumes": [
"application\/json"
@@ -19645,7 +19645,7 @@
},
"\/migrations\/{migrationId}": {
"get": {
- "summary": "Get Migration",
+ "summary": "Get migration",
"operationId": "migrationsGet",
"consumes": [
"application\/json"
@@ -19705,7 +19705,7 @@
]
},
"patch": {
- "summary": "Retry Migration",
+ "summary": "Retry migration",
"operationId": "migrationsRetry",
"consumes": [
"application\/json"
@@ -19765,7 +19765,7 @@
]
},
"delete": {
- "summary": "Delete Migration",
+ "summary": "Delete migration",
"operationId": "migrationsDelete",
"consumes": [
"application\/json"
@@ -19908,7 +19908,7 @@
},
"\/project\/variables": {
"get": {
- "summary": "List Variables",
+ "summary": "List variables",
"operationId": "projectListVariables",
"consumes": [
"application\/json"
@@ -19958,7 +19958,7 @@
]
},
"post": {
- "summary": "Create Variable",
+ "summary": "Create variable",
"operationId": "projectCreateVariable",
"consumes": [
"application\/json"
@@ -20037,7 +20037,7 @@
},
"\/project\/variables\/{variableId}": {
"get": {
- "summary": "Get Variable",
+ "summary": "Get variable",
"operationId": "projectGetVariable",
"consumes": [
"application\/json"
@@ -20097,7 +20097,7 @@
]
},
"put": {
- "summary": "Update Variable",
+ "summary": "Update variable",
"operationId": "projectUpdateVariable",
"consumes": [
"application\/json"
@@ -20181,7 +20181,7 @@
]
},
"delete": {
- "summary": "Delete Variable",
+ "summary": "Delete variable",
"operationId": "projectDeleteVariable",
"consumes": [
"application\/json"
@@ -21748,7 +21748,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21808,7 +21808,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -21904,7 +21904,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "keys.read",
"platforms": [
"console"
],
@@ -21972,7 +21972,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -22069,7 +22069,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "keys.write",
"platforms": [
"console"
],
@@ -22280,7 +22280,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -22340,7 +22340,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22464,7 +22464,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.read",
+ "scope": "platforms.read",
"platforms": [
"console"
],
@@ -22532,7 +22532,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -22631,7 +22631,7 @@
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
- "scope": "projects.write",
+ "scope": "platforms.write",
"platforms": [
"console"
],
@@ -23101,7 +23101,8 @@
"default": "",
"x-example": "tls",
"enum": [
- "tls"
+ "tls",
+ "ssl"
],
"x-enum-name": "SMTPSecure",
"x-enum-keys": []
@@ -25101,7 +25102,7 @@
},
"\/proxy\/rules": {
"get": {
- "summary": "List Rules",
+ "summary": "List rules",
"operationId": "proxyListRules",
"consumes": [
"application\/json"
@@ -25174,7 +25175,7 @@
]
},
"post": {
- "summary": "Create Rule",
+ "summary": "Create rule",
"operationId": "proxyCreateRule",
"consumes": [
"application\/json"
@@ -25265,7 +25266,7 @@
},
"\/proxy\/rules\/{ruleId}": {
"get": {
- "summary": "Get Rule",
+ "summary": "Get rule",
"operationId": "proxyGetRule",
"consumes": [
"application\/json"
@@ -25325,7 +25326,7 @@
]
},
"delete": {
- "summary": "Delete Rule",
+ "summary": "Delete rule",
"operationId": "proxyDeleteRule",
"consumes": [
"application\/json"
@@ -25382,7 +25383,7 @@
},
"\/proxy\/rules\/{ruleId}\/verification": {
"patch": {
- "summary": "Update Rule Verification Status",
+ "summary": "Update rule verification status",
"operationId": "proxyUpdateRuleVerification",
"consumes": [
"application\/json"
@@ -26014,7 +26015,7 @@
"tags": [
"storage"
],
- "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\n\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\n\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\n\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\n",
+ "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\r\n\r\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\r\n\r\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\r\n\r\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\r\n",
"responses": {
"201": {
"description": "File",
@@ -26265,7 +26266,7 @@
]
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"consumes": [
"application\/json"
@@ -26596,7 +26597,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -27386,7 +27388,7 @@
"tags": [
"teams"
],
- "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\n\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\n\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \n\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\n",
+ "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\r\n\r\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\r\n\r\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \r\n\r\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\r\n",
"responses": {
"201": {
"description": "Membership",
@@ -27575,7 +27577,7 @@
"tags": [
"teams"
],
- "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\n",
+ "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -27737,7 +27739,7 @@
"tags": [
"teams"
],
- "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\n\nIf the request is successful, a session for the user is automatically created.\n",
+ "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\r\n\r\nIf the request is successful, a session for the user is automatically created.\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -28324,7 +28326,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"consumes": [
"application\/json"
@@ -29369,7 +29371,7 @@
"tags": [
"users"
],
- "description": "Update the user labels by its unique ID. \n\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
+ "description": "Update the user labels by its unique ID. \r\n\r\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
"responses": {
"200": {
"description": "User",
@@ -29661,7 +29663,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -29737,7 +29739,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"consumes": [
"application\/json"
@@ -29800,7 +29802,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -29861,7 +29863,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -29922,7 +29924,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -30442,7 +30444,7 @@
"tags": [
"users"
],
- "description": "Creates a session for a user. Returns an immediately usable session object.\n\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
+ "description": "Creates a session for a user. Returns an immediately usable session object.\r\n\r\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
"responses": {
"201": {
"description": "Session",
@@ -30697,7 +30699,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"consumes": [
"application\/json"
@@ -30771,7 +30773,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"consumes": [
"application\/json"
@@ -30886,7 +30888,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"consumes": [
"application\/json"
@@ -30956,7 +30958,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"consumes": [
"application\/json"
@@ -31133,7 +31135,7 @@
"tags": [
"users"
],
- "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\n",
+ "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -31368,7 +31370,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories": {
"get": {
- "summary": "List Repositories",
+ "summary": "List repositories",
"operationId": "vcsListRepositories",
"consumes": [
"application\/json"
@@ -31594,7 +31596,7 @@
},
"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches": {
"get": {
- "summary": "List Repository Branches",
+ "summary": "List repository branches",
"operationId": "vcsListRepositoryBranches",
"consumes": [
"application\/json"
@@ -32046,7 +32048,7 @@
]
},
"delete": {
- "summary": "Delete Installation",
+ "summary": "Delete installation",
"operationId": "vcsDeleteInstallation",
"consumes": [
"application\/json"
@@ -33456,6 +33458,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -33475,6 +33487,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -33513,6 +33527,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -33540,7 +33564,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -33578,6 +33604,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -33605,7 +33641,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -33643,6 +33681,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -33655,7 +33703,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -33693,6 +33743,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33711,6 +33771,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33749,6 +33811,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -33775,6 +33847,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -33814,6 +33888,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33832,6 +33916,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33870,6 +33956,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -33888,6 +33984,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33926,6 +34024,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -33944,6 +34052,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -33982,6 +34092,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -34019,6 +34139,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -34067,6 +34189,16 @@
},
"x-example": [],
"x-nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -34074,7 +34206,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -36104,9 +36238,9 @@
"format": "int32"
},
"responseBody": {
- "type": "string",
+ "type": "payload",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
@@ -37270,6 +37404,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total databases storage in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"databases": {
"type": "array",
"description": "Aggregated number of databases per period.",
@@ -37296,6 +37436,15 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "An array of the aggregated number of databases storage in bytes per period.",
+ "items": {
+ "type": "object",
+ "$ref": "#\/definitions\/metric"
+ },
+ "x-example": []
}
},
"required": [
@@ -37303,9 +37452,11 @@
"databasesTotal",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"databases",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageDatabase": {
@@ -37329,6 +37480,12 @@
"x-example": 0,
"format": "int32"
},
+ "storageTotal": {
+ "type": "integer",
+ "description": "Total aggregated number of total storage used in bytes.",
+ "x-example": 0,
+ "format": "int32"
+ },
"collections": {
"type": "array",
"description": "Aggregated number of collections per period.",
@@ -37346,14 +37503,25 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
+ },
+ "storage": {
+ "type": "array",
+ "description": "Aggregated storage used in bytes per period.",
+ "items": {
+ "type": "object",
+ "$ref": "#\/definitions\/metric"
+ },
+ "x-example": []
}
},
"required": [
"range",
"collectionsTotal",
"documentsTotal",
+ "storageTotal",
"collections",
- "documents"
+ "documents",
+ "storage"
]
},
"usageCollection": {
@@ -37921,6 +38089,12 @@
"x-example": 0,
"format": "int32"
},
+ "databasesStorageTotal": {
+ "type": "integer",
+ "description": "Total aggregated sum of databases storage size (in bytes).",
+ "x-example": 0,
+ "format": "int32"
+ },
"usersTotal": {
"type": "integer",
"description": "Total aggregated number of users.",
@@ -38023,6 +38197,15 @@
},
"x-example": []
},
+ "databasesStorageBreakdown": {
+ "type": "array",
+ "description": "An array of the aggregated breakdown of storage usage by databases.",
+ "items": {
+ "type": "object",
+ "$ref": "#\/definitions\/metricBreakdown"
+ },
+ "x-example": []
+ },
"executionsMbSecondsBreakdown": {
"type": "array",
"description": "Aggregated breakdown in totals of execution mbSeconds by functions.",
@@ -38055,6 +38238,7 @@
"executionsTotal",
"documentsTotal",
"databasesTotal",
+ "databasesStorageTotal",
"usersTotal",
"filesStorageTotal",
"functionsStorageTotal",
@@ -38069,6 +38253,7 @@
"executions",
"executionsBreakdown",
"bucketsBreakdown",
+ "databasesStorageBreakdown",
"executionsMbSecondsBreakdown",
"buildsMbSecondsBreakdown",
"functionsStorageBreakdown"
diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json
index af6274226f..80c9e6037f 100644
--- a/app/config/specs/swagger2-latest-server.json
+++ b/app/config/specs/swagger2-latest-server.json
@@ -238,7 +238,7 @@
"tags": [
"account"
],
- "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\n",
+ "description": "Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request.\r\nThis endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.\r\n",
"responses": {
"200": {
"description": "User",
@@ -310,7 +310,7 @@
},
"\/account\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "accountListIdentities",
"consumes": [
"application\/json"
@@ -640,7 +640,7 @@
},
"\/account\/mfa\/authenticators\/{type}": {
"post": {
- "summary": "Create Authenticator",
+ "summary": "Create authenticator",
"operationId": "accountCreateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -709,7 +709,7 @@
]
},
"put": {
- "summary": "Verify Authenticator",
+ "summary": "Verify authenticator",
"operationId": "accountUpdateMfaAuthenticator",
"consumes": [
"application\/json"
@@ -796,7 +796,7 @@
]
},
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "accountDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -862,7 +862,7 @@
},
"\/account\/mfa\/challenge": {
"post": {
- "summary": "Create MFA Challenge",
+ "summary": "Create MFA challenge",
"operationId": "accountCreateMfaChallenge",
"consumes": [
"application\/json"
@@ -941,7 +941,7 @@
]
},
"put": {
- "summary": "Create MFA Challenge (confirmation)",
+ "summary": "Create MFA challenge (confirmation)",
"operationId": "accountUpdateMfaChallenge",
"consumes": [
"application\/json"
@@ -1019,7 +1019,7 @@
},
"\/account\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "accountListMfaFactors",
"consumes": [
"application\/json"
@@ -1075,7 +1075,7 @@
},
"\/account\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "accountGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1129,7 +1129,7 @@
]
},
"post": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "accountCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1183,7 +1183,7 @@
]
},
"patch": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "accountUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -1705,7 +1705,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
+ "description": "Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST \/account\/recovery](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createRecovery) endpoint.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.",
"responses": {
"200": {
"description": "Token",
@@ -1953,7 +1953,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Session",
@@ -2518,7 +2518,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2604,7 +2604,7 @@
"tags": [
"account"
],
- "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\n",
+ "description": "Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).\r\n",
"responses": {
"201": {
"description": "Token",
@@ -2699,7 +2699,7 @@
"tags": [
"account"
],
- "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \n\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. \r\n\r\nIf authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"301": {
"description": "No content"
@@ -2834,7 +2834,7 @@
"tags": [
"account"
],
- "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\n\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
+ "description": "Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST \/v1\/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.\r\n\r\nA user is limited to 10 active sessions at a time by default. [Learn more about session limits](https:\/\/appwrite.io\/docs\/authentication-security#limits).",
"responses": {
"201": {
"description": "Token",
@@ -2917,7 +2917,7 @@
"tags": [
"account"
],
- "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\n\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\n",
+ "description": "Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#updateVerification). The verification link sent to the user's email address is valid for 7 days.\r\n\r\nPlease note that in order to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -3214,7 +3214,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
+ "description": "You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET \/account\/sessions](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.",
"responses": {
"200": {
"description": "Image",
@@ -3345,7 +3345,7 @@
"tags": [
"avatars"
],
- "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -3480,7 +3480,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image",
@@ -3549,7 +3549,7 @@
"tags": [
"avatars"
],
- "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) standard.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4042,7 +4042,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\n\nThis endpoint does not follow HTTP redirects.",
+ "description": "Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.\r\n\r\nThis endpoint does not follow HTTP redirects.",
"responses": {
"200": {
"description": "Image",
@@ -4131,7 +4131,7 @@
"tags": [
"avatars"
],
- "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\n\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\n\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\n",
+ "description": "Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.\r\n\r\nYou can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.\r\n\r\nWhen one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4228,7 +4228,7 @@
"tags": [
"avatars"
],
- "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\n",
+ "description": "Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image.\r\n",
"responses": {
"200": {
"description": "Image",
@@ -4400,7 +4400,7 @@
"tags": [
"databases"
],
- "description": "Create a new Database.\n",
+ "description": "Create a new Database.\r\n",
"responses": {
"201": {
"description": "Database",
@@ -5217,7 +5217,7 @@
"tags": [
"databases"
],
- "description": "Create a boolean attribute.\n",
+ "description": "Create a boolean attribute.\r\n",
"responses": {
"202": {
"description": "AttributeBoolean",
@@ -5653,7 +5653,7 @@
"tags": [
"databases"
],
- "description": "Create an email attribute.\n",
+ "description": "Create an email attribute.\r\n",
"responses": {
"202": {
"description": "AttributeEmail",
@@ -5760,7 +5760,7 @@
"tags": [
"databases"
],
- "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an email attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEmail",
@@ -5871,7 +5871,7 @@
"tags": [
"databases"
],
- "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \n",
+ "description": "Create an enumeration attribute. The `elements` param acts as a white-list of accepted values for this attribute. \r\n",
"responses": {
"202": {
"description": "AttributeEnum",
@@ -5988,7 +5988,7 @@
"tags": [
"databases"
],
- "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an enum attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeEnum",
@@ -6109,7 +6109,7 @@
"tags": [
"databases"
],
- "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create a float attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeFloat",
@@ -6228,7 +6228,7 @@
"tags": [
"databases"
],
- "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a float attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeFloat",
@@ -6353,7 +6353,7 @@
"tags": [
"databases"
],
- "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\n",
+ "description": "Create an integer attribute. Optionally, minimum and maximum values can be provided.\r\n",
"responses": {
"202": {
"description": "AttributeInteger",
@@ -6472,7 +6472,7 @@
"tags": [
"databases"
],
- "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an integer attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeInteger",
@@ -6597,7 +6597,7 @@
"tags": [
"databases"
],
- "description": "Create IP address attribute.\n",
+ "description": "Create IP address attribute.\r\n",
"responses": {
"202": {
"description": "AttributeIP",
@@ -6704,7 +6704,7 @@
"tags": [
"databases"
],
- "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an ip attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeIP",
@@ -6815,7 +6815,7 @@
"tags": [
"databases"
],
- "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Create relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"202": {
"description": "AttributeRelationship",
@@ -6951,7 +6951,7 @@
"tags": [
"databases"
],
- "description": "Create a string attribute.\n",
+ "description": "Create a string attribute.\r\n",
"responses": {
"202": {
"description": "AttributeString",
@@ -7071,7 +7071,7 @@
"tags": [
"databases"
],
- "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update a string attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeString",
@@ -7188,7 +7188,7 @@
"tags": [
"databases"
],
- "description": "Create a URL attribute.\n",
+ "description": "Create a URL attribute.\r\n",
"responses": {
"202": {
"description": "AttributeURL",
@@ -7295,7 +7295,7 @@
"tags": [
"databases"
],
- "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\n",
+ "description": "Update an url attribute. Changing the `default` value will not update already existing documents.\r\n",
"responses": {
"200": {
"description": "AttributeURL",
@@ -7586,7 +7586,7 @@
"tags": [
"databases"
],
- "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\n",
+ "description": "Update relationship attribute. [Learn more about relationship attributes](https:\/\/appwrite.io\/docs\/databases-relationships#relationship-attributes).\r\n",
"responses": {
"200": {
"description": "AttributeRelationship",
@@ -8250,7 +8250,7 @@
"tags": [
"databases"
],
- "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\nAttributes can be `key`, `fulltext`, and `unique`.",
+ "description": "Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.\r\nAttributes can be `key`, `fulltext`, and `unique`.",
"responses": {
"202": {
"description": "Index",
@@ -8917,7 +8917,7 @@
"tags": [
"functions"
],
- "description": "List allowed function specifications for this instance.\n",
+ "description": "List allowed function specifications for this instance.\r\n",
"responses": {
"200": {
"description": "Specifications List",
@@ -9415,7 +9415,7 @@
"tags": [
"functions"
],
- "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\n\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.",
+ "description": "Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID.\r\n\r\nThis endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https:\/\/appwrite.io\/docs\/functions).\r\n\r\nUse the \"command\" param to set the entrypoint used to execute your code.",
"responses": {
"202": {
"description": "Deployment",
@@ -10231,7 +10231,7 @@
"tags": [
"functions"
],
- "description": "Delete a function execution by its unique ID.\n",
+ "description": "Delete a function execution by its unique ID.\r\n",
"responses": {
"204": {
"description": "No content"
@@ -11494,7 +11494,7 @@
"tags": [
"health"
],
- "description": "Returns the amount of failed jobs in a given queue.\n",
+ "description": "Returns the amount of failed jobs in a given queue.\r\n",
"responses": {
"200": {
"description": "Health Queue",
@@ -12265,7 +12265,7 @@
"tags": [
"locale"
],
- "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\n\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
+ "description": "Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language.\r\n\r\n([IP Geolocation by DB-IP](https:\/\/db-ip.com))",
"responses": {
"200": {
"description": "Locale",
@@ -12312,7 +12312,7 @@
},
"\/locale\/codes": {
"get": {
- "summary": "List Locale Codes",
+ "summary": "List locale codes",
"operationId": "localeListCodes",
"consumes": [
"application\/json"
@@ -12968,7 +12968,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -13302,7 +13302,7 @@
"tags": [
"messaging"
],
- "description": "Update a push notification by its unique ID.\n",
+ "description": "Update a push notification by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -13596,7 +13596,7 @@
"tags": [
"messaging"
],
- "description": "Update an email message by its unique ID.\n",
+ "description": "Update an email message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -13715,7 +13715,7 @@
"tags": [
"messaging"
],
- "description": "Get a message by its unique ID.\n",
+ "description": "Get a message by its unique ID.\r\n",
"responses": {
"200": {
"description": "Message",
@@ -16355,7 +16355,7 @@
"tags": [
"messaging"
],
- "description": "Get a provider by its unique ID.\n",
+ "description": "Get a provider by its unique ID.\r\n",
"responses": {
"200": {
"description": "Provider",
@@ -16803,7 +16803,7 @@
"tags": [
"messaging"
],
- "description": "Get a topic by its unique ID.\n",
+ "description": "Get a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -16866,7 +16866,7 @@
"tags": [
"messaging"
],
- "description": "Update a topic by its unique ID.\n",
+ "description": "Update a topic by its unique ID.\r\n",
"responses": {
"200": {
"description": "Topic",
@@ -17270,7 +17270,7 @@
"tags": [
"messaging"
],
- "description": "Get a subscriber by its unique ID.\n",
+ "description": "Get a subscriber by its unique ID.\r\n",
"responses": {
"200": {
"description": "Subscriber",
@@ -17981,7 +17981,7 @@
"tags": [
"storage"
],
- "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\n\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\n\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\n\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\n",
+ "description": "Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/storage#storageCreateBucket) API or directly from your Appwrite console.\r\n\r\nLarger files should be uploaded using multiple requests with the [content-range](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes.\r\n\r\nWhen the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in `x-appwrite-id` header to allow the server to know that the partial upload is for the existing file and not for a new one.\r\n\r\nIf you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally.\r\n",
"responses": {
"201": {
"description": "File",
@@ -18238,7 +18238,7 @@
]
},
"delete": {
- "summary": "Delete File",
+ "summary": "Delete file",
"operationId": "storageDeleteFile",
"consumes": [
"application\/json"
@@ -18575,7 +18575,8 @@
"jpeg",
"gif",
"png",
- "webp"
+ "webp",
+ "avif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -19149,7 +19150,7 @@
"tags": [
"teams"
],
- "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\n\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\n\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \n\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\n",
+ "description": "Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team.\r\n\r\nYou only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters.\r\n\r\nUse the `url` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. \r\n\r\nPlease note that to avoid a [Redirect Attack](https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.\r\n",
"responses": {
"201": {
"description": "Membership",
@@ -19342,7 +19343,7 @@
"tags": [
"teams"
],
- "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\n",
+ "description": "Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https:\/\/appwrite.io\/docs\/permissions).\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -19508,7 +19509,7 @@
"tags": [
"teams"
],
- "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\n\nIf the request is successful, a session for the user is automatically created.\n",
+ "description": "Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.\r\n\r\nIf the request is successful, a session for the user is automatically created.\r\n",
"responses": {
"200": {
"description": "Membership",
@@ -20105,7 +20106,7 @@
},
"\/users\/identities": {
"get": {
- "summary": "List Identities",
+ "summary": "List identities",
"operationId": "usersListIdentities",
"consumes": [
"application\/json"
@@ -21087,7 +21088,7 @@
"tags": [
"users"
],
- "description": "Update the user labels by its unique ID. \n\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
+ "description": "Update the user labels by its unique ID. \r\n\r\nLabels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https:\/\/appwrite.io\/docs\/permissions) for more info.",
"responses": {
"200": {
"description": "User",
@@ -21383,7 +21384,7 @@
},
"\/users\/{userId}\/mfa\/authenticators\/{type}": {
"delete": {
- "summary": "Delete Authenticator",
+ "summary": "Delete authenticator",
"operationId": "usersDeleteMfaAuthenticator",
"consumes": [
"application\/json"
@@ -21460,7 +21461,7 @@
},
"\/users\/{userId}\/mfa\/factors": {
"get": {
- "summary": "List Factors",
+ "summary": "List factors",
"operationId": "usersListMfaFactors",
"consumes": [
"application\/json"
@@ -21524,7 +21525,7 @@
},
"\/users\/{userId}\/mfa\/recovery-codes": {
"get": {
- "summary": "Get MFA Recovery Codes",
+ "summary": "Get MFA recovery codes",
"operationId": "usersGetMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -21586,7 +21587,7 @@
]
},
"put": {
- "summary": "Regenerate MFA Recovery Codes",
+ "summary": "Regenerate MFA recovery codes",
"operationId": "usersUpdateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -21648,7 +21649,7 @@
]
},
"patch": {
- "summary": "Create MFA Recovery Codes",
+ "summary": "Create MFA recovery codes",
"operationId": "usersCreateMfaRecoveryCodes",
"consumes": [
"application\/json"
@@ -22175,7 +22176,7 @@
"tags": [
"users"
],
- "description": "Creates a session for a user. Returns an immediately usable session object.\n\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
+ "description": "Creates a session for a user. Returns an immediately usable session object.\r\n\r\nIf you want to generate a token for a custom authentication flow, use the [POST \/users\/{userId}\/tokens](https:\/\/appwrite.io\/docs\/server\/users#createToken) endpoint.",
"responses": {
"201": {
"description": "Session",
@@ -22434,7 +22435,7 @@
},
"\/users\/{userId}\/targets": {
"get": {
- "summary": "List User Targets",
+ "summary": "List user targets",
"operationId": "usersListTargets",
"consumes": [
"application\/json"
@@ -22509,7 +22510,7 @@
]
},
"post": {
- "summary": "Create User Target",
+ "summary": "Create user target",
"operationId": "usersCreateTarget",
"consumes": [
"application\/json"
@@ -22625,7 +22626,7 @@
},
"\/users\/{userId}\/targets\/{targetId}": {
"get": {
- "summary": "Get User Target",
+ "summary": "Get user target",
"operationId": "usersGetTarget",
"consumes": [
"application\/json"
@@ -22696,7 +22697,7 @@
]
},
"patch": {
- "summary": "Update User target",
+ "summary": "Update user target",
"operationId": "usersUpdateTarget",
"consumes": [
"application\/json"
@@ -22875,7 +22876,7 @@
"tags": [
"users"
],
- "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\n",
+ "description": "Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT \/account\/sessions\/token](https:\/\/appwrite.io\/docs\/references\/cloud\/client-web\/account#createSession) endpoint to complete the login process.\r\n",
"responses": {
"201": {
"description": "Token",
@@ -24166,6 +24167,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"size": {
"type": "integer",
"description": "Attribute size.",
@@ -24185,6 +24196,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"size"
]
},
@@ -24223,6 +24236,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "integer",
"description": "Minimum value to enforce for new documents.",
@@ -24250,7 +24273,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeFloat": {
@@ -24288,6 +24313,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"min": {
"type": "number",
"description": "Minimum value to enforce for new documents.",
@@ -24315,7 +24350,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeBoolean": {
@@ -24353,6 +24390,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"default": {
"type": "boolean",
"description": "Default value for attribute when not provided. Cannot be set when attribute is required.",
@@ -24365,7 +24412,9 @@
"type",
"status",
"error",
- "required"
+ "required",
+ "$createdAt",
+ "$updatedAt"
]
},
"attributeEmail": {
@@ -24403,6 +24452,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24421,6 +24480,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24459,6 +24520,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"elements": {
"type": "array",
"description": "Array of elements in enumerated type.",
@@ -24485,6 +24556,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"elements",
"format"
]
@@ -24524,6 +24597,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24542,6 +24625,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24580,6 +24665,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "String format.",
@@ -24598,6 +24693,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24636,6 +24733,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"format": {
"type": "string",
"description": "ISO 8601 format.",
@@ -24654,6 +24761,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"format"
]
},
@@ -24692,6 +24801,16 @@
"x-example": false,
"x-nullable": true
},
+ "$createdAt": {
+ "type": "string",
+ "description": "Attribute creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Attribute update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
"relatedCollection": {
"type": "string",
"description": "The ID of the related collection.",
@@ -24729,6 +24848,8 @@
"status",
"error",
"required",
+ "$createdAt",
+ "$updatedAt",
"relatedCollection",
"relationType",
"twoWay",
@@ -24777,6 +24898,16 @@
},
"x-example": [],
"x-nullable": true
+ },
+ "$createdAt": {
+ "type": "string",
+ "description": "Index creation date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
+ },
+ "$updatedAt": {
+ "type": "string",
+ "description": "Index update date in ISO 8601 format.",
+ "x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
@@ -24784,7 +24915,9 @@
"type",
"status",
"error",
- "attributes"
+ "attributes",
+ "$createdAt",
+ "$updatedAt"
]
},
"document": {
@@ -26458,9 +26591,9 @@
"format": "int32"
},
"responseBody": {
- "type": "string",
+ "type": "payload",
"description": "HTTP response body. This will return empty unless execution is created as synchronous.",
- "x-example": "Developers are awesome."
+ "x-example": ""
},
"responseHeaders": {
"type": "array",
diff --git a/app/config/storage/mimes.php b/app/config/storage/mimes.php
index 5d315f45bc..26aaf8e1ff 100644
--- a/app/config/storage/mimes.php
+++ b/app/config/storage/mimes.php
@@ -6,6 +6,8 @@ return [
'image/gif',
'image/png',
'image/webp',
+ // 'image/heic',
+ 'image/avif',
// Video Files
'video/mp4',
@@ -31,6 +33,7 @@ return [
'audio/ogg', // Ogg Vorbis RFC 5334
'audio/vorbis', // Vorbis RFC 5215
'audio/vnd.wav', // wav RFC 2361
+ 'audio/x-wav', // php reads .wav as this - https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
'audio/aac', //AAC audio
'audio/x-hx-aac-adts', // AAC audio
diff --git a/app/config/storage/outputs.php b/app/config/storage/outputs.php
index 507a9ce667..cde2a9f38a 100644
--- a/app/config/storage/outputs.php
+++ b/app/config/storage/outputs.php
@@ -6,4 +6,7 @@ return [ // Accepted outputs files
'gif' => 'image/gif',
'png' => 'image/png',
'webp' => 'image/webp',
+ // 'heic' => 'image/heic',
+ // 'heics' => 'image/heic',
+ 'avif' => 'image/avif'
];
diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php
index d32836d0ec..a097cbdd2e 100644
--- a/app/controllers/api/account.php
+++ b/app/controllers/api/account.php
@@ -42,6 +42,7 @@ use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Queries;
+use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\UID;
@@ -4310,7 +4311,7 @@ App::post('/v1/account/targets/push')
$device = $detector->getDevice();
- $sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret);
+ $sessionId = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret);
$session = $dbForProject->getDocument('sessions', $sessionId);
try {
@@ -4379,7 +4380,9 @@ App::put('/v1/account/targets/:targetId/push')
}
if ($identifier) {
- $target->setAttribute('identifier', $identifier);
+ $target
+ ->setAttribute('identifier', $identifier)
+ ->setAttribute('expired', false);
}
$detector = new Detector($request->getUserAgent());
@@ -4482,6 +4485,12 @@ App::get('/v1/account/identities')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$identityId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('identities', $identityId);
diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php
index f6044dd624..dadd9da5e3 100644
--- a/app/controllers/api/avatars.php
+++ b/app/controllers/api/avatars.php
@@ -55,7 +55,7 @@ $avatarCallback = function (string $type, string $code, int $width, int $height,
$output = (empty($output)) ? $type : $output;
$data = $image->output($output, $quality);
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
+ ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType('image/png')
->file($data);
unset($image);
@@ -275,7 +275,7 @@ App::get('/v1/avatars/image')
$data = $image->output($output, $quality);
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
+ ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType('image/png')
->file($data);
unset($image);
@@ -409,7 +409,7 @@ App::get('/v1/avatars/favicon')
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND, 'Favicon not found');
}
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
+ ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType('image/x-icon')
->file($data);
}
@@ -420,7 +420,7 @@ App::get('/v1/avatars/favicon')
$data = $image->output($output, $quality);
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
+ ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType('image/png')
->file($data);
unset($image);
@@ -461,7 +461,7 @@ App::get('/v1/avatars/qr')
$image->crop((int) $size, (int) $size);
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->setContentType('image/png')
->send($image->output('png', 9));
});
@@ -544,7 +544,7 @@ App::get('/v1/avatars/initials')
$image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->setContentType('image/png')
->file($image->getImageBlob());
});
@@ -609,9 +609,9 @@ App::get('/v1/cards/cloud')
$isPlatinum = $user->getInternalId() % 100 === 0;
} else {
- $name = $mock === 'normal-long' ? 'Sir First Walter O\'Brien Junior' : 'Walter O\'Brien';
+ $name = $mock === 'normal-long' ? 'Sir First Walter O\'Brian Junior' : 'Walter O\'Brian';
$createdAt = new \DateTime('now');
- $githubName = $mock === 'normal-no-github' ? '' : ($mock === 'normal-long' ? 'sir-first-walterobrien-junior' : 'walterobrien');
+ $githubName = $mock === 'normal-no-github' ? '' : ($mock === 'normal-long' ? 'sir-first-walterobrian-junior' : 'walterobrian');
$isHero = $mock === 'hero';
$isContributor = $mock === 'contributor';
$isEmployee = \str_starts_with($mock, 'employee');
@@ -751,7 +751,7 @@ App::get('/v1/cards/cloud')
}
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->setContentType('image/png')
->file($baseImage->getImageBlob());
});
@@ -829,7 +829,7 @@ App::get('/v1/cards/cloud-back')
}
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->setContentType('image/png')
->file($baseImage->getImageBlob());
});
@@ -900,9 +900,9 @@ App::get('/v1/cards/cloud-og')
} else {
$bgVariation = \str_ends_with($mock, '-bg2') ? '2' : (\str_ends_with($mock, '-bg3') ? '3' : '1');
$cardVariation = \str_ends_with($mock, '-right') ? '2' : (\str_ends_with($mock, '-middle') ? '3' : '1');
- $name = \str_starts_with($mock, 'normal-long') ? 'Sir First Walter O\'Brien Junior' : 'Walter O\'Brien';
+ $name = \str_starts_with($mock, 'normal-long') ? 'Sir First Walter O\'Brian Junior' : 'Walter O\'Brian';
$createdAt = new \DateTime('now');
- $githubName = $mock === 'normal-no-github' ? '' : (\str_starts_with($mock, 'normal-long') ? 'sir-first-walterobrien-junior' : 'walterobrien');
+ $githubName = $mock === 'normal-no-github' ? '' : (\str_starts_with($mock, 'normal-long') ? 'sir-first-walterobrian-junior' : 'walterobrian');
$isHero = \str_starts_with($mock, 'hero');
$isContributor = \str_starts_with($mock, 'contributor');
$isEmployee = \str_starts_with($mock, 'employee');
@@ -1219,7 +1219,7 @@ App::get('/v1/cards/cloud-og')
}
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->setContentType('image/png')
->file($baseImage->getImageBlob());
});
diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php
index a9bb58df4b..942f886417 100644
--- a/app/controllers/api/databases.php
+++ b/app/controllers/api/databases.php
@@ -5,6 +5,7 @@ use Appwrite\Detector\Detector;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
+use Appwrite\Event\Usage;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Email;
use Appwrite\Utopia\Database\Validator\CustomId;
@@ -39,6 +40,7 @@ use Utopia\Database\Validator\Index as IndexValidator;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\Permissions;
use Utopia\Database\Validator\Queries;
+use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\Structure;
@@ -437,6 +439,7 @@ App::post('/v1/databases')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].create')
->label('scope', 'databases.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'database.create')
->label('audits.resource', 'database/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -452,7 +455,8 @@ App::post('/v1/databases')
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
- ->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents) {
+ ->inject('queueForUsage')
+ ->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents, Usage $queueForUsage) {
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
@@ -502,6 +506,7 @@ App::post('/v1/databases')
}
$queueForEvents->setParam('databaseId', $database->getId());
+ $queueForUsage->addMetric(str_replace(['{databaseInternalId}'], [$database->getInternalId()], METRIC_DATABASE_ID_STORAGE), 1); // per database
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -512,6 +517,7 @@ App::get('/v1/databases')
->desc('List databases')
->groups(['api', 'database'])
->label('scope', 'databases.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'list')
@@ -543,6 +549,13 @@ App::get('/v1/databases')
});
$cursor = reset($cursor);
if ($cursor) {
+ /** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$databaseId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('databases', $databaseId);
@@ -565,6 +578,7 @@ App::get('/v1/databases/:databaseId')
->desc('Get database')
->groups(['api', 'database'])
->label('scope', 'databases.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'get')
@@ -590,6 +604,7 @@ App::get('/v1/databases/:databaseId/logs')
->desc('List database logs')
->groups(['api', 'database'])
->label('scope', 'databases.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listLogs')
@@ -681,6 +696,7 @@ App::put('/v1/databases/:databaseId')
->desc('Update database')
->groups(['api', 'database', 'schema'])
->label('scope', 'databases.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].update')
->label('audits.event', 'database.update')
->label('audits.resource', 'database/{response.$id}')
@@ -719,6 +735,7 @@ App::delete('/v1/databases/:databaseId')
->desc('Delete database')
->groups(['api', 'database', 'schema'])
->label('scope', 'databases.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].delete')
->label('audits.event', 'database.delete')
->label('audits.resource', 'database/{request.databaseId}')
@@ -733,7 +750,8 @@ App::delete('/v1/databases/:databaseId')
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
- ->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
+ ->inject('queueForUsage')
+ ->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Usage $queueForUsage) {
$database = $dbForProject->getDocument('databases', $databaseId);
@@ -756,6 +774,9 @@ App::delete('/v1/databases/:databaseId')
->setParam('databaseId', $database->getId())
->setPayload($response->output($database, Response::MODEL_DATABASE));
+ $queueForUsage
+ ->addMetric(METRIC_DATABASES_STORAGE, 1); // Global, deletion forces full recalculation
+
$response->noContent();
});
@@ -764,6 +785,7 @@ App::post('/v1/databases/:databaseId/collections')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'collection.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -831,6 +853,7 @@ App::get('/v1/databases/:databaseId/collections')
->desc('List collections')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listCollections')
@@ -871,6 +894,12 @@ App::get('/v1/databases/:databaseId/collections')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$collectionId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId);
@@ -894,6 +923,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId')
->desc('Get collection')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getCollection')
@@ -928,6 +958,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
->desc('List collection logs')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listCollectionLogs')
@@ -1028,6 +1059,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
->desc('Update collection')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].update')
->label('audits.event', 'collection.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -1091,6 +1123,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
->desc('Delete collection')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].delete')
->label('audits.event', 'collection.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -1147,6 +1180,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -1204,6 +1238,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email'
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1246,6 +1281,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1293,6 +1329,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1335,6 +1372,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1377,6 +1415,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1448,6 +1487,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float'
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1522,6 +1562,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1563,6 +1604,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1607,6 +1649,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'attribute.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.namespace', 'databases')
@@ -1734,6 +1777,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
->desc('List attributes')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listAttributes')
@@ -1781,6 +1825,11 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
$cursor = \reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$attributeId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->find('attributes', [
Query::equal('collectionInternalId', [$collection->getInternalId()]),
@@ -1812,6 +1861,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
->desc('Get attribute')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getAttribute')
@@ -1886,6 +1936,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin
->desc('Update string attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -1929,6 +1980,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/email
->desc('Update email attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -1970,6 +2022,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/
->desc('Update enum attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2013,6 +2066,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:k
->desc('Update IP address attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2054,6 +2108,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/url/:
->desc('Update URL attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2095,6 +2150,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ
->desc('Update integer attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2146,6 +2202,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float
->desc('Update float attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2197,6 +2254,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/boole
->desc('Update boolean attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2237,6 +2295,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/datet
->desc('Update dateTime attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2277,6 +2336,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
->desc('Update relationship attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2334,6 +2394,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->desc('Delete attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2350,7 +2411,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
- ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
+ ->inject('queueForUsage')
+ ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Usage $queueForUsage) {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -2435,6 +2497,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->setContext('database', $db)
->setPayload($response->output($attribute, $model));
+ $queueForUsage
+ ->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$db->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
+
$response->noContent();
});
@@ -2444,6 +2509,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create')
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'index.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -2498,7 +2564,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
'required' => true,
'array' => false,
'default' => null,
- 'size' => 36
+ 'size' => Database::LENGTH_KEY
];
$oldAttributes[] = [
@@ -2613,6 +2679,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
->desc('List indexes')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listIndexes')
@@ -2656,6 +2723,11 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$indexId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [
Query::equal('collectionInternalId', [$collection->getInternalId()]),
@@ -2683,6 +2755,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->desc('Get index')
->groups(['api', 'database'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getIndex')
@@ -2722,6 +2795,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->desc('Delete index')
->groups(['api', 'database'])
->label('scope', 'collections.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].update')
->label('audits.event', 'index.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
@@ -2787,6 +2861,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create')
->label('scope', 'documents.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'document.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
@@ -2810,8 +2885,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->inject('dbForProject')
->inject('user')
->inject('queueForEvents')
+ ->inject('queueForUsage')
->inject('mode')
- ->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode) {
+ ->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, string $mode) {
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -3027,6 +3103,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->setContext('database', $database)
->setPayload($response->getPayload(), sensitive: $relationships);
+
+ $queueForUsage
+ ->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
});
App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
@@ -3034,6 +3113,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
->desc('List documents')
->groups(['api', 'database'])
->label('scope', 'documents.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listDocuments')
@@ -3079,6 +3159,12 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
$cursor = \reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
+
$documentId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId));
@@ -3189,6 +3275,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
->desc('Get document')
->groups(['api', 'database'])
->label('scope', 'documents.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getDocument')
@@ -3281,6 +3368,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
->desc('List document logs')
->groups(['api', 'database'])
->label('scope', 'documents.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'listDocumentLogs')
@@ -3386,6 +3474,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update')
->label('scope', 'documents.write')
+ ->label('resourceType', 'databases')
->label('audits.event', 'document.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}')
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
@@ -3621,6 +3710,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->desc('Delete document')
->groups(['api', 'database'])
->label('scope', 'documents.write')
+ ->label('resourceType', 'databases')
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].delete')
->label('audits.event', 'document.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{request.documentId}')
@@ -3641,10 +3731,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
- ->inject('queueForDeletes')
->inject('queueForEvents')
+ ->inject('queueForUsage')
->inject('mode')
- ->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, string $mode) {
+ ->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, Usage $queueForUsage, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
@@ -3717,10 +3807,6 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
)
);
- $queueForDeletes
- ->setType(DELETE_TYPE_AUDIT)
- ->setDocument($document);
-
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
@@ -3729,6 +3815,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->setContext('database', $database)
->setPayload($response->output($document, Response::MODEL_DOCUMENT), sensitive: $relationships);
+ $queueForUsage
+ ->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
+
$response->noContent();
});
@@ -3736,6 +3825,7 @@ App::get('/v1/databases/usage')
->desc('Get databases usage stats')
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getUsage')
@@ -3754,6 +3844,7 @@ App::get('/v1/databases/usage')
METRIC_DATABASES,
METRIC_COLLECTIONS,
METRIC_DOCUMENTS,
+ METRIC_DATABASES_STORAGE
];
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) {
@@ -3804,9 +3895,11 @@ App::get('/v1/databases/usage')
'databasesTotal' => $usage[$metrics[0]]['total'],
'collectionsTotal' => $usage[$metrics[1]]['total'],
'documentsTotal' => $usage[$metrics[2]]['total'],
+ 'storageTotal' => $usage[$metrics[3]]['total'],
'databases' => $usage[$metrics[0]]['data'],
'collections' => $usage[$metrics[1]]['data'],
'documents' => $usage[$metrics[2]]['data'],
+ 'storage' => $usage[$metrics[3]]['data'],
]), Response::MODEL_USAGE_DATABASES);
});
@@ -3814,6 +3907,7 @@ App::get('/v1/databases/:databaseId/usage')
->desc('Get database usage stats')
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getDatabaseUsage')
@@ -3838,6 +3932,7 @@ App::get('/v1/databases/:databaseId/usage')
$metrics = [
str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS),
str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS),
+ str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_STORAGE)
];
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) {
@@ -3888,8 +3983,10 @@ App::get('/v1/databases/:databaseId/usage')
'range' => $range,
'collectionsTotal' => $usage[$metrics[0]]['total'],
'documentsTotal' => $usage[$metrics[1]]['total'],
+ 'storageTotal' => $usage[$metrics[2]]['total'],
'collections' => $usage[$metrics[0]]['data'],
'documents' => $usage[$metrics[1]]['data'],
+ 'storage' => $usage[$metrics[2]]['data'],
]), Response::MODEL_USAGE_DATABASE);
});
@@ -3898,6 +3995,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
->desc('Get collection usage stats')
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
+ ->label('resourceType', 'databases')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'getCollectionUsage')
diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php
index 9c3e6782b4..7de443625e 100644
--- a/app/controllers/api/functions.php
+++ b/app/controllers/api/functions.php
@@ -11,7 +11,6 @@ use Appwrite\Event\Validator\FunctionEvent;
use Appwrite\Extend\Exception;
use Appwrite\Extend\Exception as AppwriteException;
use Appwrite\Functions\Validator\Headers;
-use Appwrite\Functions\Validator\Payload;
use Appwrite\Functions\Validator\RuntimeSpecification;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Platform\Tasks\ScheduleExecutions;
@@ -38,6 +37,7 @@ 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\Query\Cursor;
use Utopia\Database\Validator\Roles;
use Utopia\Database\Validator\UID;
use Utopia\Storage\Device;
@@ -138,6 +138,7 @@ App::post('/v1/functions')
->desc('Create function')
->label('scope', 'functions.write')
->label('event', 'functions.[functionId].create')
+ ->label('resourceType', 'functions')
->label('audits.event', 'function.create')
->label('audits.resource', 'function/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -400,6 +401,7 @@ App::get('/v1/functions')
->groups(['api', 'functions'])
->desc('List functions')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'list')
@@ -432,6 +434,12 @@ App::get('/v1/functions')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$functionId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('functions', $functionId);
@@ -454,6 +462,7 @@ App::get('/v1/functions/runtimes')
->groups(['api', 'functions'])
->desc('List runtimes')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listRuntimes')
@@ -487,6 +496,7 @@ App::get('/v1/functions/specifications')
->groups(['api', 'functions'])
->desc('List available function runtime specifications')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listSpecifications')
@@ -523,6 +533,7 @@ App::get('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Get function')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'get')
@@ -547,6 +558,7 @@ App::get('/v1/functions/:functionId/usage')
->desc('Get function usage')
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getFunctionUsage')
@@ -651,6 +663,7 @@ App::get('/v1/functions/usage')
->desc('Get functions usage')
->groups(['api', 'functions'])
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getUsage')
@@ -750,6 +763,7 @@ App::put('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Update function')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].update')
->label('audits.event', 'function.update')
->label('audits.resource', 'function/{response.$id}')
@@ -952,6 +966,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
->groups(['api', 'functions'])
->desc('Download deployment')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getDeploymentDownload')
@@ -988,7 +1003,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
$response
->setContentType('application/gzip')
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"');
@@ -1037,6 +1052,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Update deployment')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].deployments.[deploymentId].update')
->label('audits.event', 'deployment.update')
->label('audits.resource', 'function/{request.functionId}')
@@ -1099,6 +1115,7 @@ App::delete('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Delete function')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].delete')
->label('audits.event', 'function.delete')
->label('audits.resource', 'function/{request.functionId}')
@@ -1146,6 +1163,7 @@ App::post('/v1/functions/:functionId/deployments')
->groups(['api', 'functions'])
->desc('Create deployment')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].deployments.[deploymentId].create')
->label('audits.event', 'deployment.create')
->label('audits.resource', 'function/{request.functionId}')
@@ -1365,6 +1383,7 @@ App::get('/v1/functions/:functionId/deployments')
->groups(['api', 'functions'])
->desc('List deployments')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listDeployments')
@@ -1408,6 +1427,12 @@ App::get('/v1/functions/:functionId/deployments')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$deploymentId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('deployments', $deploymentId);
@@ -1442,6 +1467,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Get deployment')
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getDeployment')
@@ -1485,6 +1511,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Delete deployment')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].deployments.[deploymentId].delete')
->label('audits.event', 'deployment.delete')
->label('audits.resource', 'function/{request.functionId}')
@@ -1550,6 +1577,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/build')
->groups(['api', 'functions'])
->desc('Rebuild deployment')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].deployments.[deploymentId].update')
->label('audits.event', 'deployment.update')
->label('audits.resource', 'function/{request.functionId}')
@@ -1618,6 +1646,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId/build')
->groups(['api', 'functions'])
->desc('Cancel deployment')
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('audits.event', 'deployment.update')
->label('audits.resource', 'function/{request.functionId}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -1707,7 +1736,9 @@ App::post('/v1/functions/:functionId/executions')
->groups(['api', 'functions'])
->desc('Create execution')
->label('scope', 'execution.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].executions.[executionId].create')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createExecution')
@@ -1717,7 +1748,7 @@ App::post('/v1/functions/:functionId/executions')
->label('sdk.response.model', Response::MODEL_EXECUTION)
->label('sdk.request.type', Response::CONTENT_TYPE_JSON)
->param('functionId', '', new UID(), 'Function ID.')
- ->param('body', '', new Payload(10485760, 0), 'HTTP body of execution. Default value is empty string.', true)
+ ->param('body', '', new Text(10485760, 0), 'HTTP body of execution. Default value is empty string.', true)
->param('async', false, new Boolean(true), 'Execute code in the background. Default value is false.', true)
->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'], true), 'HTTP method of execution. Default value is GET.', true)
@@ -2109,6 +2140,7 @@ App::get('/v1/functions/:functionId/executions')
->groups(['api', 'functions'])
->desc('List executions')
->label('scope', 'execution.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listExecutions')
@@ -2154,6 +2186,12 @@ App::get('/v1/functions/:functionId/executions')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$executionId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('executions', $executionId);
@@ -2190,6 +2228,7 @@ App::get('/v1/functions/:functionId/executions/:executionId')
->groups(['api', 'functions'])
->desc('Get execution')
->label('scope', 'execution.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getExecution')
@@ -2237,6 +2276,7 @@ App::delete('/v1/functions/:functionId/executions/:executionId')
->groups(['api', 'functions'])
->desc('Delete execution')
->label('scope', 'execution.write')
+ ->label('resourceType', 'functions')
->label('event', 'functions.[functionId].executions.[executionId].delete')
->label('audits.event', 'executions.delete')
->label('audits.resource', 'function/{request.functionId}')
@@ -2307,6 +2347,7 @@ App::post('/v1/functions/:functionId/variables')
->desc('Create variable')
->groups(['api', 'functions'])
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('audits.event', 'variable.create')
->label('audits.resource', 'function/{request.functionId}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -2371,6 +2412,7 @@ App::get('/v1/functions/:functionId/variables')
->desc('List variables')
->groups(['api', 'functions'])
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listVariables')
@@ -2398,6 +2440,7 @@ App::get('/v1/functions/:functionId/variables/:variableId')
->desc('Get variable')
->groups(['api', 'functions'])
->label('scope', 'functions.read')
+ ->label('resourceType', 'functions')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getVariable')
@@ -2437,6 +2480,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
->desc('Update variable')
->groups(['api', 'functions'])
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('audits.event', 'variable.update')
->label('audits.resource', 'function/{request.functionId}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -2498,6 +2542,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId')
->desc('Delete variable')
->groups(['api', 'functions'])
->label('scope', 'functions.write')
+ ->label('resourceType', 'functions')
->label('audits.event', 'variable.delete')
->label('audits.resource', 'function/{request.functionId}')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -2546,6 +2591,7 @@ App::get('/v1/functions/templates')
->groups(['api'])
->desc('List function templates')
->label('scope', 'public')
+ ->label('resourceType', 'functions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listTemplates')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
@@ -2583,6 +2629,7 @@ App::get('/v1/functions/templates')
App::get('/v1/functions/templates/:templateId')
->desc('Get function template')
->label('scope', 'public')
+ ->label('resourceType', 'functions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getTemplate')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php
index 2917bc8416..1f042d2239 100644
--- a/app/controllers/api/locale.php
+++ b/app/controllers/api/locale.php
@@ -63,7 +63,7 @@ App::get('/v1/locale')
$response
->addHeader('Cache-Control', 'public, max-age=' . $time)
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
;
$response->dynamic(new Document($output), Response::MODEL_LOCALE);
});
diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php
index 7da0348a8f..50fd30420e 100644
--- a/app/controllers/api/messaging.php
+++ b/app/controllers/api/messaging.php
@@ -32,6 +32,7 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Queries;
+use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\Roles;
@@ -55,6 +56,7 @@ App::post('/v1/messaging/providers/mailgun')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createMailgunProvider')
@@ -142,6 +144,7 @@ App::post('/v1/messaging/providers/sendgrid')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createSendgridProvider')
@@ -217,6 +220,7 @@ App::post('/v1/messaging/providers/smtp')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createSmtpProvider')
@@ -304,6 +308,7 @@ App::post('/v1/messaging/providers/msg91')
->label('audits.event', 'provider.create')
->label('audits.resource', 'provider/{response.$id}')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('event', 'providers.[providerId].create')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
@@ -381,6 +386,7 @@ App::post('/v1/messaging/providers/telesign')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createTelesignProvider')
@@ -458,6 +464,7 @@ App::post('/v1/messaging/providers/textmagic')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createTextmagicProvider')
@@ -535,6 +542,7 @@ App::post('/v1/messaging/providers/twilio')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createTwilioProvider')
@@ -612,6 +620,7 @@ App::post('/v1/messaging/providers/vonage')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createVonageProvider')
@@ -689,6 +698,7 @@ App::post('/v1/messaging/providers/fcm')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createFcmProvider')
@@ -752,6 +762,7 @@ App::post('/v1/messaging/providers/apns')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createApnsProvider')
@@ -835,6 +846,7 @@ App::get('/v1/messaging/providers')
->desc('List providers')
->groups(['api', 'messaging'])
->label('scope', 'providers.read')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listProviders')
@@ -866,6 +878,11 @@ App::get('/v1/messaging/providers')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$providerId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId));
@@ -886,6 +903,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
->desc('List provider logs')
->groups(['api', 'messaging'])
->label('scope', 'providers.read')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listProviderLogs')
@@ -974,6 +992,7 @@ App::get('/v1/messaging/providers/:providerId')
->desc('Get provider')
->groups(['api', 'messaging'])
->label('scope', 'providers.read')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'getProvider')
@@ -1001,6 +1020,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateMailgunProvider')
@@ -1107,6 +1127,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateSendgridProvider')
@@ -1198,6 +1219,7 @@ App::patch('/v1/messaging/providers/smtp/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateSmtpProvider')
@@ -1320,6 +1342,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateMsg91Provider')
@@ -1400,6 +1423,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateTelesignProvider')
@@ -1482,6 +1506,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateTextmagicProvider')
@@ -1564,6 +1589,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateTwilioProvider')
@@ -1646,6 +1672,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateVonageProvider')
@@ -1728,6 +1755,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateFcmProvider')
@@ -1797,6 +1825,7 @@ App::patch('/v1/messaging/providers/apns/:providerId')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateApnsProvider')
@@ -1892,6 +1921,7 @@ App::delete('/v1/messaging/providers/:providerId')
->label('audits.resource', 'provider/{request.$providerId}')
->label('event', 'providers.[providerId].delete')
->label('scope', 'providers.write')
+ ->label('resourceType', 'providers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'deleteProvider')
@@ -1927,6 +1957,7 @@ App::post('/v1/messaging/topics')
->label('audits.resource', 'topic/{response.$id}')
->label('event', 'topics.[topicId].create')
->label('scope', 'topics.write')
+ ->label('resourceType', 'topics')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createTopic')
@@ -1967,6 +1998,7 @@ App::get('/v1/messaging/topics')
->desc('List topics')
->groups(['api', 'messaging'])
->label('scope', 'topics.read')
+ ->label('resourceType', 'topics')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listTopics')
@@ -1998,6 +2030,11 @@ App::get('/v1/messaging/topics')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$topicId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
@@ -2018,6 +2055,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
->desc('List topic logs')
->groups(['api', 'messaging'])
->label('scope', 'topics.read')
+ ->label('resourceType', 'topics')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listTopicLogs')
@@ -2107,6 +2145,7 @@ App::get('/v1/messaging/topics/:topicId')
->desc('Get topic')
->groups(['api', 'messaging'])
->label('scope', 'topics.read')
+ ->label('resourceType', 'topics')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'getTopic')
@@ -2135,6 +2174,7 @@ App::patch('/v1/messaging/topics/:topicId')
->label('audits.resource', 'topic/{response.$id}')
->label('event', 'topics.[topicId].update')
->label('scope', 'topics.write')
+ ->label('resourceType', 'topics')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateTopic')
@@ -2179,6 +2219,7 @@ App::delete('/v1/messaging/topics/:topicId')
->label('audits.resource', 'topic/{request.$topicId}')
->label('event', 'topics.[topicId].delete')
->label('scope', 'topics.write')
+ ->label('resourceType', 'topics')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'deleteTopic')
@@ -2219,6 +2260,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
->label('audits.resource', 'subscriber/{response.$id}')
->label('event', 'topics.[topicId].subscribers.[subscriberId].create')
->label('scope', 'subscribers.write')
+ ->label('resourceType', 'subscribers')
->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createSubscriber')
@@ -2312,6 +2354,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
->desc('List subscribers')
->groups(['api', 'messaging'])
->label('scope', 'subscribers.read')
+ ->label('resourceType', 'subscribers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listSubscribers')
@@ -2352,6 +2395,11 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$subscriberId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId));
@@ -2386,6 +2434,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
->desc('List subscriber logs')
->groups(['api', 'messaging'])
->label('scope', 'subscribers.read')
+ ->label('resourceType', 'subscribers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listSubscriberLogs')
@@ -2475,6 +2524,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
->desc('Get subscriber')
->groups(['api', 'messaging'])
->label('scope', 'subscribers.read')
+ ->label('resourceType', 'subscribers')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'getSubscriber')
@@ -2517,6 +2567,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
->label('audits.resource', 'subscriber/{request.$subscriberId}')
->label('event', 'topics.[topicId].subscribers.[subscriberId].delete')
->label('scope', 'subscribers.write')
+ ->label('resourceType', 'subscribers')
->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'deleteSubscriber')
@@ -2576,6 +2627,7 @@ App::post('/v1/messaging/messages/email')
->label('audits.resource', 'message/{response.$id}')
->label('event', 'messages.[messageId].create')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createEmail')
@@ -2728,6 +2780,7 @@ App::post('/v1/messaging/messages/sms')
->label('audits.resource', 'message/{response.$id}')
->label('event', 'messages.[messageId].create')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createSms')
@@ -2844,6 +2897,7 @@ App::post('/v1/messaging/messages/push')
->label('audits.resource', 'message/{response.$id}')
->label('event', 'messages.[messageId].create')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createPush')
@@ -3017,6 +3071,7 @@ App::get('/v1/messaging/messages')
->desc('List messages')
->groups(['api', 'messaging'])
->label('scope', 'messages.read')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listMessages')
@@ -3048,6 +3103,11 @@ App::get('/v1/messaging/messages')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$messageId = $cursor->getValue();
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('messages', $messageId));
@@ -3068,6 +3128,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
->desc('List message logs')
->groups(['api', 'messaging'])
->label('scope', 'messages.read')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listMessageLogs')
@@ -3157,6 +3218,7 @@ App::get('/v1/messaging/messages/:messageId/targets')
->desc('List message targets')
->groups(['api', 'messaging'])
->label('scope', 'messages.read')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'listTargets')
@@ -3202,6 +3264,11 @@ App::get('/v1/messaging/messages/:messageId/targets')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$targetId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('targets', $targetId);
@@ -3222,6 +3289,7 @@ App::get('/v1/messaging/messages/:messageId')
->desc('Get message')
->groups(['api', 'messaging'])
->label('scope', 'messages.read')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'getMessage')
@@ -3249,6 +3317,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
->label('audits.resource', 'message/{response.$id}')
->label('event', 'messages.[messageId].update')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateEmail')
@@ -3449,6 +3518,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->label('audits.resource', 'message/{response.$id}')
->label('event', 'messages.[messageId].update')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateSms')
@@ -3604,6 +3674,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
->label('audits.resource', 'message/{response.$id}')
->label('event', 'messages.[messageId].update')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updatePush')
@@ -3842,6 +3913,7 @@ App::delete('/v1/messaging/messages/:messageId')
->label('audits.resource', 'message/{request.messageId}')
->label('event', 'messages.[messageId].delete')
->label('scope', 'messages.write')
+ ->label('resourceType', 'messages')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'delete')
diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php
index 374a5575a7..a4880cef86 100644
--- a/app/controllers/api/migrations.php
+++ b/app/controllers/api/migrations.php
@@ -16,6 +16,7 @@ use Utopia\Database\Document;
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\UID;
use Utopia\Migration\Sources\Appwrite;
use Utopia\Migration\Sources\Firebase;
@@ -60,6 +61,7 @@ App::post('/v1/migrations/appwrite')
'status' => 'pending',
'stage' => 'init',
'source' => Appwrite::getName(),
+ 'destination' => Appwrite::getName(),
'credentials' => [
'endpoint' => $endpoint,
'projectId' => $projectId,
@@ -164,6 +166,7 @@ App::post('/v1/migrations/firebase/oauth')
'status' => 'pending',
'stage' => 'init',
'source' => Firebase::getName(),
+ 'destination' => Appwrite::getName(),
'credentials' => [
'serviceAccount' => json_encode($serviceAccount),
],
@@ -224,6 +227,7 @@ App::post('/v1/migrations/firebase')
'status' => 'pending',
'stage' => 'init',
'source' => Firebase::getName(),
+ 'destination' => Appwrite::getName(),
'credentials' => [
'serviceAccount' => $serviceAccount,
],
@@ -279,6 +283,7 @@ App::post('/v1/migrations/supabase')
'status' => 'pending',
'stage' => 'init',
'source' => Supabase::getName(),
+ 'destination' => Appwrite::getName(),
'credentials' => [
'endpoint' => $endpoint,
'apiKey' => $apiKey,
@@ -340,6 +345,7 @@ App::post('/v1/migrations/nhost')
'status' => 'pending',
'stage' => 'init',
'source' => NHost::getName(),
+ 'destination' => Appwrite::getName(),
'credentials' => [
'subdomain' => $subdomain,
'region' => $region,
@@ -404,6 +410,12 @@ App::get('/v1/migrations')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$migrationId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('migrations', $migrationId);
diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php
index 62a34bb5ce..6053326308 100644
--- a/app/controllers/api/project.php
+++ b/app/controllers/api/project.php
@@ -47,6 +47,7 @@ App::get('/v1/project/usage')
METRIC_USERS,
METRIC_BUCKETS,
METRIC_FILES_STORAGE,
+ METRIC_DATABASES_STORAGE,
METRIC_DEPLOYMENTS_STORAGE,
METRIC_BUILDS_STORAGE
],
@@ -56,6 +57,7 @@ App::get('/v1/project/usage')
METRIC_NETWORK_OUTBOUND,
METRIC_USERS,
METRIC_EXECUTIONS,
+ METRIC_DATABASES_STORAGE,
METRIC_EXECUTIONS_MB_SECONDS,
METRIC_BUILDS_MB_SECONDS
]
@@ -182,6 +184,23 @@ App::get('/v1/project/usage')
];
}, $dbForProject->find('buckets'));
+ $databasesStorageBreakdown = array_map(function ($database) use ($dbForProject) {
+ $id = $database->getId();
+ $name = $database->getAttribute('name');
+ $metric = str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_STORAGE);
+
+ $value = $dbForProject->findOne('stats', [
+ Query::equal('metric', [$metric]),
+ Query::equal('period', ['inf'])
+ ]);
+
+ return [
+ 'resourceId' => $id,
+ 'name' => $name,
+ 'value' => $value['value'] ?? 0,
+ ];
+ }, $dbForProject->find('databases'));
+
$functionsStorageBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
@@ -269,6 +288,7 @@ App::get('/v1/project/usage')
'buildsMbSecondsTotal' => $total[METRIC_BUILDS_MB_SECONDS],
'documentsTotal' => $total[METRIC_DOCUMENTS],
'databasesTotal' => $total[METRIC_DATABASES],
+ 'databasesStorageTotal' => $total[METRIC_DATABASES_STORAGE],
'usersTotal' => $total[METRIC_USERS],
'bucketsTotal' => $total[METRIC_BUCKETS],
'filesStorageTotal' => $total[METRIC_FILES_STORAGE],
@@ -279,6 +299,7 @@ App::get('/v1/project/usage')
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown,
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown,
'bucketsBreakdown' => $bucketsBreakdown,
+ 'databasesStorageBreakdown' => $databasesStorageBreakdown,
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown,
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown,
'functionsStorageBreakdown' => $functionsStorageBreakdown,
diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php
index 3a8c232195..3bfa416bd8 100644
--- a/app/controllers/api/projects.php
+++ b/app/controllers/api/projects.php
@@ -31,6 +31,7 @@ use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
+use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\UID;
use Utopia\Domains\Validator\PublicDomain;
use Utopia\DSN\DSN;
@@ -279,6 +280,12 @@ App::get('/v1/projects')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$projectId = $cursor->getValue();
$cursorDocument = $dbForConsole->getDocument('projects', $projectId);
@@ -923,6 +930,7 @@ App::delete('/v1/projects/:projectId')
}
$queueForDeletes
+ ->setProject($project)
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($project);
@@ -1199,7 +1207,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
App::post('/v1/projects/:projectId/keys')
->desc('Create key')
->groups(['api', 'projects'])
- ->label('scope', 'projects.write')
+ ->label('scope', 'keys.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createKey')
@@ -1249,7 +1257,7 @@ App::post('/v1/projects/:projectId/keys')
App::get('/v1/projects/:projectId/keys')
->desc('List keys')
->groups(['api', 'projects'])
- ->label('scope', 'projects.read')
+ ->label('scope', 'keys.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listKeys')
@@ -1281,7 +1289,7 @@ App::get('/v1/projects/:projectId/keys')
App::get('/v1/projects/:projectId/keys/:keyId')
->desc('Get key')
->groups(['api', 'projects'])
- ->label('scope', 'projects.read')
+ ->label('scope', 'keys.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getKey')
@@ -1315,7 +1323,7 @@ App::get('/v1/projects/:projectId/keys/:keyId')
App::put('/v1/projects/:projectId/keys/:keyId')
->desc('Update key')
->groups(['api', 'projects'])
- ->label('scope', 'projects.write')
+ ->label('scope', 'keys.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateKey')
@@ -1361,7 +1369,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
App::delete('/v1/projects/:projectId/keys/:keyId')
->desc('Delete key')
->groups(['api', 'projects'])
- ->label('scope', 'projects.write')
+ ->label('scope', 'keys.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteKey')
@@ -1436,7 +1444,7 @@ App::post('/v1/projects/:projectId/platforms')
->desc('Create platform')
->groups(['api', 'projects'])
->label('audits.event', 'platforms.create')
- ->label('scope', 'projects.write')
+ ->label('scope', 'platforms.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createPlatform')
@@ -1486,7 +1494,7 @@ App::post('/v1/projects/:projectId/platforms')
App::get('/v1/projects/:projectId/platforms')
->desc('List platforms')
->groups(['api', 'projects'])
- ->label('scope', 'projects.read')
+ ->label('scope', 'platforms.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listPlatforms')
@@ -1518,7 +1526,7 @@ App::get('/v1/projects/:projectId/platforms')
App::get('/v1/projects/:projectId/platforms/:platformId')
->desc('Get platform')
->groups(['api', 'projects'])
- ->label('scope', 'projects.read')
+ ->label('scope', 'platforms.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getPlatform')
@@ -1552,7 +1560,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
App::put('/v1/projects/:projectId/platforms/:platformId')
->desc('Update platform')
->groups(['api', 'projects'])
- ->label('scope', 'projects.write')
+ ->label('scope', 'platforms.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updatePlatform')
@@ -1600,7 +1608,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
->desc('Delete platform')
->groups(['api', 'projects'])
->label('audits.event', 'platforms.delete')
- ->label('scope', 'projects.write')
+ ->label('scope', 'platforms.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deletePlatform')
@@ -1744,7 +1752,7 @@ App::post('/v1/projects/:projectId/smtp/tests')
->param('port', 587, new Integer(), 'SMTP server port', true)
->param('username', '', new Text(0, 0), 'SMTP server username', true)
->param('password', '', new Text(0, 0), 'SMTP server password', true)
- ->param('secure', '', new WhiteList(['tls'], true), 'Does SMTP server use secure connection', true)
+ ->param('secure', '', new WhiteList(['tls', 'ssl'], true), 'Does SMTP server use secure connection', true)
->inject('response')
->inject('dbForConsole')
->inject('queueForMails')
diff --git a/app/controllers/api/proxy.php b/app/controllers/api/proxy.php
index 84484a7209..984a9fb974 100644
--- a/app/controllers/api/proxy.php
+++ b/app/controllers/api/proxy.php
@@ -13,6 +13,7 @@ use Utopia\Database\Document;
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\UID;
use Utopia\Domains\Domain;
use Utopia\Logger\Log;
@@ -185,6 +186,12 @@ App::get('/v1/proxy/rules')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$ruleId = $cursor->getValue();
$cursorDocument = $dbForConsole->getDocument('rules', $ruleId);
diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php
index ca248c2628..afd3c4687a 100644
--- a/app/controllers/api/storage.php
+++ b/app/controllers/api/storage.php
@@ -24,6 +24,7 @@ use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Permissions;
+use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\UID;
use Utopia\Image\Image;
use Utopia\Storage\Compression\Algorithms\GZIP;
@@ -48,6 +49,7 @@ App::post('/v1/storage/buckets')
->desc('Create bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
+ ->label('resourceType', 'buckets')
->label('event', 'buckets.[bucketId].create')
->label('audits.event', 'bucket.create')
->label('audits.resource', 'bucket/{response.$id}')
@@ -146,6 +148,7 @@ App::get('/v1/storage/buckets')
->desc('List buckets')
->groups(['api', 'storage'])
->label('scope', 'buckets.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'listBuckets')
@@ -178,6 +181,12 @@ App::get('/v1/storage/buckets')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$bucketId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('buckets', $bucketId);
@@ -200,6 +209,7 @@ App::get('/v1/storage/buckets/:bucketId')
->desc('Get bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getBucket')
@@ -225,6 +235,7 @@ App::put('/v1/storage/buckets/:bucketId')
->desc('Update bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
+ ->label('resourceType', 'buckets')
->label('event', 'buckets.[bucketId].update')
->label('audits.event', 'bucket.update')
->label('audits.resource', 'bucket/{response.$id}')
@@ -292,6 +303,7 @@ App::delete('/v1/storage/buckets/:bucketId')
->desc('Delete bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
+ ->label('resourceType', 'buckets')
->label('audits.event', 'bucket.delete')
->label('event', 'buckets.[bucketId].delete')
->label('audits.resource', 'bucket/{request.bucketId}')
@@ -334,6 +346,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->desc('Create file')
->groups(['api', 'storage'])
->label('scope', 'files.write')
+ ->label('resourceType', 'buckets')
->label('audits.event', 'file.create')
->label('event', 'buckets.[bucketId].files.[fileId].create')
->label('audits.resource', 'file/{response.$id}')
@@ -695,6 +708,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
->desc('List files')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'listFiles')
@@ -744,6 +758,12 @@ App::get('/v1/storage/buckets/:bucketId/files')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$fileId = $cursor->getValue();
if ($fileSecurity && !$valid) {
@@ -780,6 +800,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
->desc('Get file')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFile')
@@ -827,6 +848,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->desc('Get file preview')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('cache', true)
->label('cache.resourceType', 'bucket/{request.bucketId}')
->label('cache.resource', 'file/{request.fileId}')
@@ -889,10 +911,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
- if ((\strpos($request->getAccept(), 'image/webp') === false) && ('webp' === $output)) { // Fallback webp to jpeg when no browser support
- $output = 'jpg';
- }
-
$inputs = Config::getParam('storage-inputs');
$outputs = Config::getParam('storage-outputs');
$fileLogos = Config::getParam('storage-logos');
@@ -990,7 +1008,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
+ ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType($contentType)
->file($data)
;
@@ -1003,6 +1021,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
->desc('Get file for download')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileDownload')
@@ -1053,7 +1072,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
$response
->setContentType($file->getAttribute('mimeType'))
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"')
;
@@ -1143,6 +1162,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
->desc('Get file for view')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileView')
@@ -1203,7 +1223,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
;
@@ -1294,6 +1314,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
->desc('Get file for push notification')
->groups(['api', 'storage'])
->label('scope', 'public')
+ ->label('resourceType', 'buckets')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', '*/*')
->label('sdk.methodType', 'location')
@@ -1357,7 +1378,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
+ ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage());
$size = $file->getAttribute('sizeOriginal', 0);
@@ -1448,6 +1469,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->desc('Update file')
->groups(['api', 'storage'])
->label('scope', 'files.write')
+ ->label('resourceType', 'buckets')
->label('event', 'buckets.[bucketId].files.[fileId].update')
->label('audits.event', 'file.update')
->label('audits.resource', 'file/{response.$id}')
@@ -1552,6 +1574,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
->desc('Delete file')
->groups(['api', 'storage'])
->label('scope', 'files.write')
+ ->label('resourceType', 'buckets')
->label('event', 'buckets.[bucketId].files.[fileId].delete')
->label('audits.event', 'file.delete')
->label('audits.resource', 'file/{request.fileId}')
@@ -1645,6 +1668,7 @@ App::get('/v1/storage/usage')
->desc('Get storage usage stats')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getUsage')
@@ -1724,6 +1748,7 @@ App::get('/v1/storage/:bucketId/usage')
->desc('Get bucket usage stats')
->groups(['api', 'storage'])
->label('scope', 'files.read')
+ ->label('resourceType', 'buckets')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getBucketUsage')
diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php
index f98cdd721c..f9abaeeb44 100644
--- a/app/controllers/api/teams.php
+++ b/app/controllers/api/teams.php
@@ -34,6 +34,7 @@ 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;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\UID;
@@ -43,6 +44,7 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Host;
use Utopia\Validator\Text;
+use Utopia\Validator\WhiteList;
App::post('/v1/teams')
->desc('Create team')
@@ -169,6 +171,12 @@ App::get('/v1/teams')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$teamId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('teams', $teamId);
@@ -394,7 +402,17 @@ App::post('/v1/teams/:teamId/memberships')
->param('email', '', new Email(), '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', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
+ ->param('roles', [], function (Document $project) {
+ if ($project->getId() === 'console') {
+ ;
+ $roles = array_keys(Config::getParam('roles', []));
+ array_filter($roles, function ($role) {
+ return !in_array($role, [Auth::USER_ROLE_APPS, Auth::USER_ROLE_GUESTS, Auth::USER_ROLE_USERS]);
+ });
+ return new ArrayList(new WhiteList($roles), APP_LIMIT_ARRAY_PARAMS_SIZE);
+ }
+ return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
+ }, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. 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, ['clients']) // TODO add our own built-in confirm page
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
->inject('response')
@@ -740,6 +758,13 @@ App::get('/v1/teams/:teamId/memberships')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
+
$membershipId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('memberships', $membershipId);
@@ -868,7 +893,17 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
->param('teamId', '', new UID(), 'Team ID.')
->param('membershipId', '', new UID(), 'Membership ID.')
- ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
+ ->param('roles', [], function (Document $project) {
+ if ($project->getId() === 'console') {
+ ;
+ $roles = array_keys(Config::getParam('roles', []));
+ array_filter($roles, function ($role) {
+ return !in_array($role, [Auth::USER_ROLE_APPS, Auth::USER_ROLE_GUESTS, Auth::USER_ROLE_USERS]);
+ });
+ return new ArrayList(new WhiteList($roles), APP_LIMIT_ARRAY_PARAMS_SIZE);
+ }
+ return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
+ }, 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
->inject('request')
->inject('response')
->inject('user')
diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php
index 3beb1526b0..c4d0df3b40 100644
--- a/app/controllers/api/users.php
+++ b/app/controllers/api/users.php
@@ -36,6 +36,7 @@ use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Queries;
+use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\UID;
@@ -558,6 +559,12 @@ App::get('/v1/users')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$userId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('users', $userId);
@@ -868,6 +875,11 @@ App::get('/v1/users/:userId/targets')
$cursor = reset($cursor);
if ($cursor) {
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$targetId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('targets', $targetId);
@@ -920,6 +932,12 @@ App::get('/v1/users/identities')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$identityId = $cursor->getValue();
$cursorDocument = $dbForProject->getDocument('identities', $identityId);
@@ -1467,7 +1485,9 @@ App::patch('/v1/users/:userId/targets/:targetId')
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
}
- $target->setAttribute('identifier', $identifier);
+ $target
+ ->setAttribute('identifier', $identifier)
+ ->setAttribute('expired', false);
}
if ($providerId) {
@@ -1481,8 +1501,9 @@ App::patch('/v1/users/:userId/targets/:targetId')
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
}
- $target->setAttribute('providerId', $provider->getId());
- $target->setAttribute('providerInternalId', $provider->getInternalId());
+ $target
+ ->setAttribute('providerId', $provider->getId())
+ ->setAttribute('providerInternalId', $provider->getInternalId());
}
if ($name) {
diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php
index f3381490ec..e79eb67936 100644
--- a/app/controllers/api/vcs.php
+++ b/app/controllers/api/vcs.php
@@ -20,6 +20,7 @@ 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\Adapter\Bun;
use Utopia\Detector\Adapter\CPP;
use Utopia\Detector\Adapter\Dart;
@@ -1069,6 +1070,12 @@ App::get('/v1/vcs/installations')
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+
+ $validator = new Cursor();
+ if (!$validator->isValid($cursor)) {
+ throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
+ }
+
$installationId = $cursor->getValue();
$cursorDocument = $dbForConsole->getDocument('installations', $installationId);
diff --git a/app/controllers/general.php b/app/controllers/general.php
index 0bbfa2b694..a5f6b38a44 100644
--- a/app/controllers/general.php
+++ b/app/controllers/general.php
@@ -6,6 +6,7 @@ use Ahc\Jwt\JWT;
use Appwrite\Auth\Auth;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
+use Appwrite\Event\Func;
use Appwrite\Event\Usage;
use Appwrite\Extend\Exception as AppwriteException;
use Appwrite\Network\Validator\Origin;
@@ -25,6 +26,7 @@ use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
+use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
@@ -44,7 +46,7 @@ Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
-function router(App $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Reader $geodb)
+function router(App $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked)
{
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
@@ -135,6 +137,10 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
}
+ if ($isResourceBlocked($project, 'functions', $functionId)) {
+ throw new AppwriteException(AppwriteException::GENERAL_RESOURCE_BLOCKED);
+ }
+
$version = $function->getAttribute('version', 'v2');
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
$spec = Config::getParam('runtime-specifications')[$function->getAttribute('specification', APP_FUNCTION_SPECIFICATION_DEFAULT)];
@@ -366,7 +372,11 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
->trigger()
;
- $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution));
+ $queueForFunctions
+ ->setType(Func::TYPE_ASYNC_WRITE)
+ ->setExecution($execution)
+ ->setProject($project)
+ ->trigger();
}
$execution->setAttribute('logs', '');
@@ -450,7 +460,9 @@ App::init()
->inject('queueForUsage')
->inject('queueForEvents')
->inject('queueForCertificates')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, Usage $queueForUsage, Event $queueForEvents, Certificate $queueForCertificates) {
+ ->inject('queueForFunctions')
+ ->inject('isResourceBlocked')
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, Usage $queueForUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, callable $isResourceBlocked) {
/*
* Appwrite Router
*/
@@ -458,7 +470,7 @@ App::init()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain) {
- if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb)) {
+ if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked)) {
return;
}
}
@@ -666,8 +678,10 @@ App::options()
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
+ ->inject('queueForFunctions')
->inject('geodb')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
+ ->inject('isResourceBlocked')
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked) {
/*
* Appwrite Router
*/
@@ -675,7 +689,7 @@ App::options()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain) {
- if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb)) {
+ if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked)) {
return;
}
}
@@ -863,8 +877,12 @@ App::error()
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
- $responseCode = $logger->addLog($log);
- Console::info('Log pushed with status code: ' . $responseCode);
+ try {
+ $responseCode = $logger->addLog($log);
+ Console::info('Error log pushed with status code: ' . $responseCode);
+ } catch (Throwable $th) {
+ Console::error('Error pushing log: ' . $th->getMessage());
+ }
}
/** Wrap all exceptions inside Appwrite\Extend\Exception */
@@ -953,8 +971,10 @@ App::get('/robots.txt')
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
+ ->inject('queueForFunctions')
->inject('geodb')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
+ ->inject('isResourceBlocked')
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -962,7 +982,7 @@ App::get('/robots.txt')
$template = new View(__DIR__ . '/../views/general/robots.phtml');
$response->text($template->render(false));
} else {
- router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb);
+ router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked);
}
});
@@ -978,8 +998,10 @@ App::get('/humans.txt')
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
+ ->inject('queueForFunctions')
->inject('geodb')
- ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
+ ->inject('isResourceBlocked')
+ ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -987,7 +1009,7 @@ App::get('/humans.txt')
$template = new View(__DIR__ . '/../views/general/humans.phtml');
$response->text($template->render(false));
} else {
- router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb);
+ router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked);
}
});
@@ -1044,6 +1066,38 @@ App::get('/.well-known/acme-challenge/*')
include_once __DIR__ . '/shared/api.php';
include_once __DIR__ . '/shared/api/auth.php';
+App::get('/v1/ping')
+ ->groups(['api', 'general'])
+ ->desc('Test the connection between the Appwrite and the SDK.')
+ ->label('scope', 'global')
+ ->label('event', 'projects.[projectId].ping')
+ ->inject('response')
+ ->inject('project')
+ ->inject('dbForConsole')
+ ->inject('queueForEvents')
+ ->action(function (Response $response, Document $project, Database $dbForConsole, Event $queueForEvents) {
+ if ($project->isEmpty()) {
+ throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
+ }
+
+ $pingCount = $project->getAttribute('pingCount', 0) + 1;
+ $pingedAt = DateTime::now();
+
+ $project
+ ->setAttribute('pingCount', $pingCount)
+ ->setAttribute('pingedAt', $pingedAt);
+
+ Authorization::skip(function () use ($dbForConsole, $project) {
+ $dbForConsole->updateDocument('projects', $project->getId(), $project);
+ });
+
+ $queueForEvents
+ ->setParam('projectId', $project->getId())
+ ->setPayload($response->output($project, Response::MODEL_PROJECT));
+
+ $response->text('Pong!');
+ });
+
App::wildcard()
->groups(['api'])
->label('scope', 'global')
diff --git a/app/controllers/mock.php b/app/controllers/mock.php
index fdb1d80dcc..bc071fc885 100644
--- a/app/controllers/mock.php
+++ b/app/controllers/mock.php
@@ -158,7 +158,7 @@ App::patch('/v1/mock/functions-v2')
App::post('/v1/mock/api-key-unprefixed')
->desc('Create API Key (without standard prefix)')
->groups(['mock', 'api', 'projects'])
- ->label('scope', 'projects.write')
+ ->label('scope', 'public')
->label('docs', false)
->param('projectId', '', new UID(), 'Project ID.')
->inject('response')
diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php
index a0151ed9ed..c5f0f3ac85 100644
--- a/app/controllers/shared/api.php
+++ b/app/controllers/shared/api.php
@@ -104,7 +104,7 @@ $usageDatabaseListener = function (string $event, Document $document, Usage $que
$databaseInternalId = $parts[1] ?? 0;
$queueForUsage
->addMetric(METRIC_COLLECTIONS, $value) // per project
- ->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value) // per database
+ ->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value)
;
if ($event === Database::EVENT_DOCUMENT_DELETE) {
@@ -169,42 +169,22 @@ App::init()
->inject('session')
->inject('servers')
->inject('mode')
- ->action(function (App $utopia, Request $request, Database $dbForConsole, Document $project, Document $user, ?Document $session, array $servers, string $mode) {
+ ->inject('team')
+ ->action(function (App $utopia, Request $request, Database $dbForConsole, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team) {
$route = $utopia->getRoute();
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
- /**
- * ACL Check
- */
+ /** Default role */
+ $roles = Config::getParam('roles', []);
$role = ($user->isEmpty())
? Role::guests()->toString()
: Role::users()->toString();
- // Add user roles
- $memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships');
-
- if ($memberships) {
- foreach ($memberships->getAttribute('roles', []) as $memberRole) {
- switch ($memberRole) {
- case 'owner':
- $role = Auth::USER_ROLE_OWNER;
- break;
- case 'admin':
- $role = Auth::USER_ROLE_ADMIN;
- break;
- case 'developer':
- $role = Auth::USER_ROLE_DEVELOPER;
- break;
- }
- }
- }
-
- $roles = Config::getParam('roles', []);
- $scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route
- $scopes = $roles[$role]['scopes']; // Allowed scopes for user role
+ /** Allowed Scopes for the role */
+ $scopes = $roles[$role]['scopes'];
$apiKey = $request->getHeader('x-appwrite-key', '');
@@ -303,13 +283,38 @@ App::init()
}
}
}
+ // Admin User Authentication
+ elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) {
+ $teamId = $team->getId();
+ $adminRoles = [];
+ $memberships = $user->getAttribute('memberships', []);
+ foreach ($memberships as $membership) {
+ if ($membership->getAttribute('confirm', false) === true && $membership->getAttribute('teamId') === $teamId) {
+ $adminRoles = $membership->getAttribute('roles', []);
+ break;
+ }
+ }
+
+ if (empty($adminRoles)) {
+ throw new Exception(Exception::USER_UNAUTHORIZED);
+ }
+
+ $scopes = []; // reset scope if admin
+ foreach ($adminRoles as $role) {
+ $scopes = \array_merge($scopes, $roles[$role]['scopes']);
+ }
+
+ Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
+ }
+
+ $scopes = \array_unique($scopes);
Authorization::setRole($role);
-
foreach (Auth::getRoles($user) as $authRole) {
Authorization::setRole($authRole);
}
+ /** Do not allow access to disabled services */
$service = $route->getLabel('sdk.namespace', '');
if (!empty($service)) {
if (
@@ -320,14 +325,14 @@ App::init()
throw new Exception(Exception::GENERAL_SERVICE_DISABLED);
}
}
- if (!\in_array($scope, $scopes)) {
- if ($project->isEmpty()) { // Check if permission is denied because project is missing
- throw new Exception(Exception::PROJECT_NOT_FOUND);
- }
+ /** Do now allow access if scope is not allowed */
+ $scope = $route->getLabel('scope', 'none');
+ if (!\in_array($scope, $scopes)) {
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')');
}
+ /** Do not allow access to blocked accounts */
if (false === $user->getAttribute('status')) { // Account is blocked
throw new Exception(Exception::USER_BLOCKED);
}
@@ -513,7 +518,7 @@ App::init()
}
$response
- ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT')
+ ->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp))
->addHeader('X-Appwrite-Cache', 'hit')
->setContentType($cacheLog->getAttribute('mimeType'))
->send($data);
@@ -521,7 +526,7 @@ App::init()
$response
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
->addHeader('Pragma', 'no-cache')
- ->addHeader('Expires', 0)
+ ->addHeader('Expires', '0')
->addHeader('X-Appwrite-Cache', 'miss')
;
}
diff --git a/app/http.php b/app/http.php
index 7e1291142b..bec772c770 100644
--- a/app/http.php
+++ b/app/http.php
@@ -298,8 +298,12 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
- $responseCode = $logger->addLog($log);
- Console::info('Log pushed with status code: ' . $responseCode);
+ try {
+ $responseCode = $logger->addLog($log);
+ Console::info('Error log pushed with status code: ' . $responseCode);
+ } catch (Throwable $th) {
+ Console::error('Error pushing log: ' . $th->getMessage());
+ }
}
Console::error('[Error] Type: ' . get_class($th));
diff --git a/app/init.php b/app/init.php
index b4ab772e0e..50ab123754 100644
--- a/app/init.php
+++ b/app/init.php
@@ -41,6 +41,7 @@ use Appwrite\Network\Validator\Email;
use Appwrite\Network\Validator\Origin;
use Appwrite\OpenSSL\OpenSSL;
use Appwrite\URL\URL as AppwriteURL;
+use Appwrite\Utopia\Request;
use MaxMind\Db\Reader;
use PHPMailer\PHPMailer\PHPMailer;
use Swoole\Database\PDOProxy;
@@ -129,6 +130,7 @@ const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange';
const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange';
const APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH = 1_073_741_824; // 2^32 bits / 4 bits per char
const APP_DATABASE_TIMEOUT_MILLISECONDS = 15_000;
+const APP_DATABASE_QUERY_MAX_VALUES = 500;
const APP_STORAGE_UPLOADS = '/storage/uploads';
const APP_STORAGE_FUNCTIONS = '/storage/functions';
const APP_STORAGE_BUILDS = '/storage/builds';
@@ -148,9 +150,12 @@ const APP_SOCIAL_DEV = 'https://dev.to/appwrite';
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=1';
const APP_HOSTNAME_INTERNAL = 'appwrite';
-const APP_FUNCTION_SPECIFICATION_DEFAULT = Specification::S_05VCPU_512MB;
+const APP_FUNCTION_SPECIFICATION_DEFAULT = Specification::S_1VCPU_512MB;
const APP_FUNCTION_CPUS_DEFAULT = 0.5;
const APP_FUNCTION_MEMORY_DEFAULT = 512;
+const APP_PLATFORM_SERVER = 'server';
+const APP_PLATFORM_CLIENT = 'client';
+const APP_PLATFORM_CONSOLE = 'console';
// Database Reconnect
const DATABASE_RECONNECT_SLEEP = 2;
@@ -238,10 +243,13 @@ const METRIC_MESSAGES_TYPE_PROVIDER_FAILED = METRIC_MESSAGES . '.{type}.{provid
const METRIC_SESSIONS = 'sessions';
const METRIC_DATABASES = 'databases';
const METRIC_COLLECTIONS = 'collections';
+const METRIC_DATABASES_STORAGE = 'databases.storage';
const METRIC_DATABASE_ID_COLLECTIONS = '{databaseInternalId}.collections';
+const METRIC_DATABASE_ID_STORAGE = '{databaseInternalId}.databases.storage';
const METRIC_DOCUMENTS = 'documents';
const METRIC_DATABASE_ID_DOCUMENTS = '{databaseInternalId}.documents';
const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collectionInternalId}.documents';
+const METRIC_DATABASE_ID_COLLECTION_ID_STORAGE = '{databaseInternalId}.{collectionInternalId}.databases.storage';
const METRIC_BUCKETS = 'buckets';
const METRIC_FILES = 'files';
const METRIC_FILES_STORAGE = 'files.storage';
@@ -1252,13 +1260,13 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
$user = new Document([]);
}
- if (APP_MODE_ADMIN === $mode) {
- if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) {
- Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
- } else {
- $user = new Document([]);
- }
- }
+ // if (APP_MODE_ADMIN === $mode) {
+ // if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) {
+ // Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
+ // } else {
+ // $user = new Document([]);
+ // }
+ // }
$authJWT = $request->getHeader('x-appwrite-jwt', '');
@@ -1335,7 +1343,7 @@ App::setResource('console', function () {
'$collection' => ID::custom('projects'),
'description' => 'Appwrite core engine',
'logo' => '',
- 'teamId' => -1,
+ 'teamId' => null,
'webhooks' => [],
'keys' => [],
'platforms' => [
@@ -1391,7 +1399,8 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole,
$database
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId())
- ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
+ ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS)
+ ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
try {
$dsn = new DSN($project->getAttribute('database'));
@@ -1427,7 +1436,8 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) {
->setNamespace('_console')
->setMetadata('host', \gethostname())
->setMetadata('project', 'console')
- ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
+ ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS)
+ ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
return $database;
}, ['pools', 'cache']);
@@ -1451,7 +1461,8 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
$database
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId())
- ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
+ ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS)
+ ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
@@ -1516,9 +1527,9 @@ App::setResource('deviceForBuilds', function ($project) {
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
}, ['project']);
-function getDevice($root): Device
+function getDevice(string $root, string $connection = ''): Device
{
- $connection = System::getEnv('_APP_CONNECTIONS_STORAGE', '');
+ $connection = !empty($connection) ? $connection : System::getEnv('_APP_CONNECTIONS_STORAGE', '');
if (!empty($connection)) {
$acl = 'private';
@@ -1760,6 +1771,43 @@ App::setResource('requestTimestamp', function ($request) {
}
return $requestTimestamp;
}, ['request']);
+
App::setResource('plan', function (array $plan = []) {
return [];
});
+
+App::setResource('team', function (Document $project, Database $dbForConsole, App $utopia, Request $request) {
+ $teamInternalId = '';
+ if ($project->getId() !== 'console') {
+ $teamInternalId = $project->getAttribute('teamInternalId', '');
+ } else {
+ $route = $utopia->match($request);
+ $path = $route->getPath();
+ if (str_starts_with($path, '/v1/projects/:projectId')) {
+ $uri = $request->getURI();
+ $pid = explode('/', $uri)[3];
+ $p = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $pid));
+ $teamInternalId = $p->getAttribute('teamInternalId', '');
+ } elseif ($path === '/v1/projects') {
+ $teamId = $request->getParam('teamId', '');
+ $team = Authorization::skip(fn () => $dbForConsole->getDocument('teams', $teamId));
+ return $team;
+ }
+ }
+
+ $team = Authorization::skip(function () use ($dbForConsole, $teamInternalId) {
+ return $dbForConsole->findOne('teams', [
+ Query::equal('$internalId', [$teamInternalId]),
+ ]);
+ });
+
+ if (!$team) {
+ $team = new Document([]);
+ }
+ return $team;
+}, ['project', 'dbForConsole', 'utopia', 'request']);
+
+App::setResource(
+ 'isResourceBlocked',
+ fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false
+);
diff --git a/app/realtime.php b/app/realtime.php
index b8fdb2cf21..1b59eb3bc7 100644
--- a/app/realtime.php
+++ b/app/realtime.php
@@ -40,7 +40,7 @@ require_once __DIR__ . '/init.php';
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
// Allows overriding
-if (!function_exists("getConsoleDB")) {
+if (!function_exists('getConsoleDB')) {
function getConsoleDB(): Database
{
global $register;
@@ -66,7 +66,7 @@ if (!function_exists("getConsoleDB")) {
}
// Allows overriding
-if (!function_exists("getProjectDB")) {
+if (!function_exists('getProjectDB')) {
function getProjectDB(Document $project): Database
{
global $register;
@@ -113,7 +113,7 @@ if (!function_exists("getProjectDB")) {
}
// Allows overriding
-if (!function_exists("getCache")) {
+if (!function_exists('getCache')) {
function getCache(): Cache
{
global $register;
@@ -135,7 +135,14 @@ if (!function_exists("getCache")) {
}
}
-$realtime = new Realtime();
+if (!function_exists('getRealtime')) {
+ function getRealtime(): Realtime
+ {
+ return new Realtime();
+ }
+}
+
+$realtime = getRealtime();
/**
* Table for statistics across all workers.
@@ -184,8 +191,12 @@ $logError = function (Throwable $error, string $action) use ($register) {
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
- $responseCode = $logger->addLog($log);
- Console::info('Realtime log pushed with status code: ' . $responseCode);
+ try {
+ $responseCode = $logger->addLog($log);
+ Console::info('Error log pushed with status code: ' . $responseCode);
+ } catch (Throwable $th) {
+ Console::error('Error pushing log: ' . $th->getMessage());
+ }
}
Console::error('[Error] Type: ' . get_class($error));
diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml
index 8f83fed544..ad35135a6f 100644
--- a/app/views/install/compose.phtml
+++ b/app/views/install/compose.phtml
@@ -531,6 +531,8 @@ $image = $this->getParam('image', '');
- _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD
- _APP_LOGGING_CONFIG
+ - _APP_DOMAIN
+ - _APP_OPTIONS_FORCE_HTTPS
appwrite-worker-messaging:
image: /:
diff --git a/app/worker.php b/app/worker.php
index 9bcdae78e6..4741afe7ea 100644
--- a/app/worker.php
+++ b/app/worker.php
@@ -272,6 +272,11 @@ Server::setResource('deviceForCache', function (Document $project) {
return getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId());
}, ['project']);
+Server::setResource(
+ 'isResourceBlocked',
+ fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false
+);
+
$pools = $register->get('pools');
$platform = new Appwrite();
@@ -346,8 +351,12 @@ $worker
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
- $responseCode = $logger->addLog($log);
- Console::info('Usage stats log pushed with status code: ' . $responseCode);
+ try {
+ $responseCode = $logger->addLog($log);
+ Console::info('Error log pushed with status code: ' . $responseCode);
+ } catch (Throwable $th) {
+ Console::error('Error pushing log: ' . $th->getMessage());
+ }
}
Console::error('[Error] Type: ' . get_class($error));
diff --git a/composer.json b/composer.json
index 91ff1eeb92..dd5472a0fa 100644
--- a/composer.json
+++ b/composer.json
@@ -43,7 +43,7 @@
"ext-openssl": "*",
"ext-zlib": "*",
"ext-sockets": "*",
- "appwrite/php-runtimes": "0.15.*",
+ "appwrite/php-runtimes": "0.16.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.43.0",
"utopia-php/analytics": "0.10.*",
@@ -51,16 +51,16 @@
"utopia-php/cache": "0.10.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
- "utopia-php/database": "0.53.*",
+ "utopia-php/database": "0.53.8",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
"utopia-php/fetch": "0.2.*",
- "utopia-php/image": "0.6.*",
+ "utopia-php/image": "0.7.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.12.*",
- "utopia-php/migration": "0.5.*",
+ "utopia-php/migration": "0.6.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "0.5.*",
@@ -69,7 +69,7 @@
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.18.*",
"utopia-php/swoole": "0.8.*",
- "utopia-php/system": "0.8.*",
+ "utopia-php/system": "0.9.*",
"utopia-php/vcs": "0.8.*",
"utopia-php/websocket": "0.1.*",
"matomo/device-detector": "6.1.*",
diff --git a/composer.lock b/composer.lock
index 147800df32..5c7d48373e 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": "b6820da26239716cf14a445697902a03",
+ "content-hash": "18505aa5baca1170e7cbdbb2a355b173",
"packages": [
{
"name": "adhocore/jwt",
@@ -65,16 +65,16 @@
},
{
"name": "appwrite/appwrite",
- "version": "10.1.0",
+ "version": "11.1.0",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-for-php.git",
- "reference": "da579af70723cfc117b5af84375bdef117e27312"
+ "reference": "1d043f543acdb17b9fdb440b1b2dd208e400bad3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/da579af70723cfc117b5af84375bdef117e27312",
- "reference": "da579af70723cfc117b5af84375bdef117e27312",
+ "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/1d043f543acdb17b9fdb440b1b2dd208e400bad3",
+ "reference": "1d043f543acdb17b9fdb440b1b2dd208e400bad3",
"shasum": ""
},
"require": {
@@ -83,7 +83,8 @@
"php": ">=7.1.0"
},
"require-dev": {
- "phpunit/phpunit": "3.7.35"
+ "mockery/mockery": "^1.6.6",
+ "phpunit/phpunit": "^10"
},
"type": "library",
"autoload": {
@@ -99,10 +100,10 @@
"support": {
"email": "team@appwrite.io",
"issues": "https://github.com/appwrite/sdk-for-php/issues",
- "source": "https://github.com/appwrite/sdk-for-php/tree/10.1.0",
+ "source": "https://github.com/appwrite/sdk-for-php/tree/11.1.0",
"url": "https://appwrite.io/support"
},
- "time": "2023-11-20T09:56:12+00:00"
+ "time": "2024-06-26T07:03:23+00:00"
},
{
"name": "appwrite/php-clamav",
@@ -156,21 +157,21 @@
},
{
"name": "appwrite/php-runtimes",
- "version": "0.15.0",
+ "version": "0.16.2",
"source": {
"type": "git",
"url": "https://github.com/appwrite/runtimes.git",
- "reference": "68ea5bcc24c513a6d641ddf9412bbab13e5dfb94"
+ "reference": "c33005e3eaaf2d427e9fd1077d5335e31f4d36f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/appwrite/runtimes/zipball/68ea5bcc24c513a6d641ddf9412bbab13e5dfb94",
- "reference": "68ea5bcc24c513a6d641ddf9412bbab13e5dfb94",
+ "url": "https://api.github.com/repos/appwrite/runtimes/zipball/c33005e3eaaf2d427e9fd1077d5335e31f4d36f9",
+ "reference": "c33005e3eaaf2d427e9fd1077d5335e31f4d36f9",
"shasum": ""
},
"require": {
"php": ">=8.0",
- "utopia-php/system": "0.8.*"
+ "utopia-php/system": "0.9.*"
},
"require-dev": {
"laravel/pint": "^1.15",
@@ -205,9 +206,9 @@
],
"support": {
"issues": "https://github.com/appwrite/runtimes/issues",
- "source": "https://github.com/appwrite/runtimes/tree/0.15.0"
+ "source": "https://github.com/appwrite/runtimes/tree/0.16.2"
},
- "time": "2024-08-21T10:23:45+00:00"
+ "time": "2024-10-09T15:02:52+00:00"
},
{
"name": "beberlei/assert",
@@ -1623,16 +1624,16 @@
},
{
"name": "utopia-php/cli",
- "version": "0.15.0",
+ "version": "0.15.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cli.git",
- "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea"
+ "reference": "d69bbe51a6a94dc4e5bcdd542b5938038b985a65"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/cli/zipball/ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea",
- "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea",
+ "url": "https://api.github.com/repos/utopia-php/cli/zipball/d69bbe51a6a94dc4e5bcdd542b5938038b985a65",
+ "reference": "d69bbe51a6a94dc4e5bcdd542b5938038b985a65",
"shasum": ""
},
"require": {
@@ -1666,9 +1667,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cli/issues",
- "source": "https://github.com/utopia-php/cli/tree/0.15.0"
+ "source": "https://github.com/utopia-php/cli/tree/0.15.1"
},
- "time": "2023-03-01T05:55:14+00:00"
+ "time": "2024-10-04T13:55:36+00:00"
},
{
"name": "utopia-php/config",
@@ -1723,16 +1724,16 @@
},
{
"name": "utopia-php/database",
- "version": "0.53.4",
+ "version": "0.53.8",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
- "reference": "36a0e89d983afc1368635282e04fa762220a1d2a"
+ "reference": "f4f9297d633b9f8407c6261535549bfd6024a468"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/database/zipball/36a0e89d983afc1368635282e04fa762220a1d2a",
- "reference": "36a0e89d983afc1368635282e04fa762220a1d2a",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/f4f9297d633b9f8407c6261535549bfd6024a468",
+ "reference": "f4f9297d633b9f8407c6261535549bfd6024a468",
"shasum": ""
},
"require": {
@@ -1773,9 +1774,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
- "source": "https://github.com/utopia-php/database/tree/0.53.4"
+ "source": "https://github.com/utopia-php/database/tree/0.53.8"
},
- "time": "2024-09-10T10:19:57+00:00"
+ "time": "2024-10-16T08:16:33+00:00"
},
{
"name": "utopia-php/domains",
@@ -1970,21 +1971,21 @@
},
{
"name": "utopia-php/image",
- "version": "0.6.1",
+ "version": "0.7.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/image.git",
- "reference": "2d74c27e69e65a93cf94a16586598a04fe435bf0"
+ "reference": "fcea143edbad524bf871ddbebe801d981f91f181"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/image/zipball/2d74c27e69e65a93cf94a16586598a04fe435bf0",
- "reference": "2d74c27e69e65a93cf94a16586598a04fe435bf0",
+ "url": "https://api.github.com/repos/utopia-php/image/zipball/fcea143edbad524bf871ddbebe801d981f91f181",
+ "reference": "fcea143edbad524bf871ddbebe801d981f91f181",
"shasum": ""
},
"require": {
"ext-imagick": "*",
- "php": ">=8.0"
+ "php": ">=8.1"
},
"require-dev": {
"laravel/pint": "1.2.*",
@@ -2012,9 +2013,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/image/issues",
- "source": "https://github.com/utopia-php/image/tree/0.6.1"
+ "source": "https://github.com/utopia-php/image/tree/0.7.0"
},
- "time": "2024-02-05T13:31:44+00:00"
+ "time": "2024-10-02T05:45:38+00:00"
},
{
"name": "utopia-php/locale",
@@ -2069,16 +2070,16 @@
},
{
"name": "utopia-php/logger",
- "version": "0.6.0",
+ "version": "0.6.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/logger.git",
- "reference": "a2d1daeeb8f61fdec6d851950d9a021a3d05c9f9"
+ "reference": "25b5bd2ad8bb51292f76332faa7034644fd0941d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/logger/zipball/a2d1daeeb8f61fdec6d851950d9a021a3d05c9f9",
- "reference": "a2d1daeeb8f61fdec6d851950d9a021a3d05c9f9",
+ "url": "https://api.github.com/repos/utopia-php/logger/zipball/25b5bd2ad8bb51292f76332faa7034644fd0941d",
+ "reference": "25b5bd2ad8bb51292f76332faa7034644fd0941d",
"shasum": ""
},
"require": {
@@ -2117,22 +2118,22 @@
],
"support": {
"issues": "https://github.com/utopia-php/logger/issues",
- "source": "https://github.com/utopia-php/logger/tree/0.6.0"
+ "source": "https://github.com/utopia-php/logger/tree/0.6.2"
},
- "time": "2024-05-23T13:37:54+00:00"
+ "time": "2024-10-14T16:02:49+00:00"
},
{
"name": "utopia-php/messaging",
- "version": "0.12.0",
+ "version": "0.12.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
- "reference": "6e466d3511981291843c6ebf9ce3f44fc75e37b0"
+ "reference": "f6790fba1fcee12163d51c65d2c226a7856295d9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/messaging/zipball/6e466d3511981291843c6ebf9ce3f44fc75e37b0",
- "reference": "6e466d3511981291843c6ebf9ce3f44fc75e37b0",
+ "url": "https://api.github.com/repos/utopia-php/messaging/zipball/f6790fba1fcee12163d51c65d2c226a7856295d9",
+ "reference": "f6790fba1fcee12163d51c65d2c226a7856295d9",
"shasum": ""
},
"require": {
@@ -2168,33 +2169,41 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
- "source": "https://github.com/utopia-php/messaging/tree/0.12.0"
+ "source": "https://github.com/utopia-php/messaging/tree/0.12.2"
},
- "time": "2024-05-30T14:58:25+00:00"
+ "time": "2024-10-22T01:02:20+00:00"
},
{
"name": "utopia-php/migration",
- "version": "0.5.2",
+ "version": "0.6.9",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
- "reference": "f18d44d4459f78c292dac9edde856fd156fe497a"
+ "reference": "ce97cdf2ca82e7cec78e2ed484ef2c71ebe8744b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/migration/zipball/f18d44d4459f78c292dac9edde856fd156fe497a",
- "reference": "f18d44d4459f78c292dac9edde856fd156fe497a",
+ "url": "https://api.github.com/repos/utopia-php/migration/zipball/ce97cdf2ca82e7cec78e2ed484ef2c71ebe8744b",
+ "reference": "ce97cdf2ca82e7cec78e2ed484ef2c71ebe8744b",
"shasum": ""
},
"require": {
- "appwrite/appwrite": "10.1.0",
- "php": "8.*"
+ "appwrite/appwrite": "11.1.*",
+ "ext-curl": "*",
+ "ext-openssl": "*",
+ "php": "8.3.*",
+ "utopia-php/database": "0.53.*",
+ "utopia-php/dsn": "0.2.*",
+ "utopia-php/framework": "0.33.*",
+ "utopia-php/storage": "0.18.*"
},
"require-dev": {
- "laravel/pint": "1.*",
- "phpunit/phpunit": "9.*",
- "utopia-php/cli": "^0.18.0",
- "vlucas/phpdotenv": "5.*"
+ "ext-pdo": "*",
+ "laravel/pint": "1.17.*",
+ "phpstan/phpstan": "1.11.*",
+ "phpunit/phpunit": "11.2.*",
+ "utopia-php/cli": "0.16.*",
+ "vlucas/phpdotenv": "5.6.*"
},
"type": "library",
"autoload": {
@@ -2216,9 +2225,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
- "source": "https://github.com/utopia-php/migration/tree/0.5.2"
+ "source": "https://github.com/utopia-php/migration/tree/0.6.9"
},
- "time": "2024-07-22T09:27:07+00:00"
+ "time": "2024-10-16T08:33:21+00:00"
},
{
"name": "utopia-php/mongo",
@@ -2705,16 +2714,16 @@
},
{
"name": "utopia-php/system",
- "version": "0.8.0",
+ "version": "0.9.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/system.git",
- "reference": "a2cbfb3c69b9ecb8b6f06c5774f3cf279ea7665e"
+ "reference": "8e4a7edaf2dfeb4c9524e9f766d27754f2c4b64d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/system/zipball/a2cbfb3c69b9ecb8b6f06c5774f3cf279ea7665e",
- "reference": "a2cbfb3c69b9ecb8b6f06c5774f3cf279ea7665e",
+ "url": "https://api.github.com/repos/utopia-php/system/zipball/8e4a7edaf2dfeb4c9524e9f766d27754f2c4b64d",
+ "reference": "8e4a7edaf2dfeb4c9524e9f766d27754f2c4b64d",
"shasum": ""
},
"require": {
@@ -2755,9 +2764,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/system/issues",
- "source": "https://github.com/utopia-php/system/tree/0.8.0"
+ "source": "https://github.com/utopia-php/system/tree/0.9.0"
},
- "time": "2024-04-01T10:22:28+00:00"
+ "time": "2024-10-09T14:44:01+00:00"
},
{
"name": "utopia-php/vcs",
@@ -2993,16 +3002,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
- "version": "0.39.21",
+ "version": "0.39.24",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
- "reference": "9754b190d33aaad56fdb8defc94f90248184c5ac"
+ "reference": "412451c87f6ef17e24e9a5cf41721043d74c60c8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9754b190d33aaad56fdb8defc94f90248184c5ac",
- "reference": "9754b190d33aaad56fdb8defc94f90248184c5ac",
+ "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/412451c87f6ef17e24e9a5cf41721043d74c60c8",
+ "reference": "412451c87f6ef17e24e9a5cf41721043d74c60c8",
"shasum": ""
},
"require": {
@@ -3038,9 +3047,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/0.39.21"
+ "source": "https://github.com/appwrite/sdk-generator/tree/0.39.24"
},
- "time": "2024-09-10T08:49:29+00:00"
+ "time": "2024-10-09T19:13:27+00:00"
},
{
"name": "doctrine/annotations",
@@ -3314,16 +3323,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.17.3",
+ "version": "v1.18.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "9d77be916e145864f10788bb94531d03e1f7b482"
+ "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/9d77be916e145864f10788bb94531d03e1f7b482",
- "reference": "9d77be916e145864f10788bb94531d03e1f7b482",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/35c00c05ec43e6b46d295efc0f4386ceb30d50d9",
+ "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9",
"shasum": ""
},
"require": {
@@ -3376,7 +3385,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2024-09-03T15:00:28+00:00"
+ "time": "2024-09-24T17:22:50+00:00"
},
{
"name": "matthiasmullie/minify",
@@ -3564,16 +3573,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.2.0",
+ "version": "v5.3.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb"
+ "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb",
- "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
+ "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
"shasum": ""
},
"require": {
@@ -3616,9 +3625,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.2.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
},
- "time": "2024-09-15T16:40:33+00:00"
+ "time": "2024-10-08T18:51:32+00:00"
},
{
"name": "phar-io/manifest",
@@ -3838,6 +3847,7 @@
"issues": "https://github.com/phpbench/dom/issues",
"source": "https://github.com/phpbench/dom/tree/0.3.3"
},
+ "abandoned": true,
"time": "2023-03-06T23:46:57+00:00"
},
{
@@ -4185,16 +4195,16 @@
},
{
"name": "phpstan/phpdoc-parser",
- "version": "1.30.1",
+ "version": "1.33.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "51b95ec8670af41009e2b2b56873bad96682413e"
+ "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e",
- "reference": "51b95ec8670af41009e2b2b56873bad96682413e",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140",
+ "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140",
"shasum": ""
},
"require": {
@@ -4226,9 +4236,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0"
},
- "time": "2024-09-07T20:13:05+00:00"
+ "time": "2024-10-13T11:25:22+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -5865,16 +5875,16 @@
},
{
"name": "symfony/console",
- "version": "v7.1.4",
+ "version": "v7.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111"
+ "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/1eed7af6961d763e7832e874d7f9b21c3ea9c111",
- "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111",
+ "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee",
+ "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee",
"shasum": ""
},
"require": {
@@ -5938,7 +5948,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.1.4"
+ "source": "https://github.com/symfony/console/tree/v7.1.5"
},
"funding": [
{
@@ -5954,7 +5964,7 @@
"type": "tidelift"
}
],
- "time": "2024-08-15T22:48:53+00:00"
+ "time": "2024-09-20T08:28:38+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -6025,16 +6035,16 @@
},
{
"name": "symfony/filesystem",
- "version": "v7.1.2",
+ "version": "v7.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "92a91985250c251de9b947a14bb2c9390b1a562c"
+ "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c",
- "reference": "92a91985250c251de9b947a14bb2c9390b1a562c",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a",
+ "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a",
"shasum": ""
},
"require": {
@@ -6071,7 +6081,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.1.2"
+ "source": "https://github.com/symfony/filesystem/tree/v7.1.5"
},
"funding": [
{
@@ -6087,7 +6097,7 @@
"type": "tidelift"
}
],
- "time": "2024-06-28T10:03:55+00:00"
+ "time": "2024-09-17T09:16:35+00:00"
},
{
"name": "symfony/finder",
@@ -6536,16 +6546,16 @@
},
{
"name": "symfony/process",
- "version": "v7.1.3",
+ "version": "v7.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca"
+ "reference": "5c03ee6369281177f07f7c68252a280beccba847"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca",
- "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca",
+ "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847",
+ "reference": "5c03ee6369281177f07f7c68252a280beccba847",
"shasum": ""
},
"require": {
@@ -6577,7 +6587,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.1.3"
+ "source": "https://github.com/symfony/process/tree/v7.1.5"
},
"funding": [
{
@@ -6593,7 +6603,7 @@
"type": "tidelift"
}
],
- "time": "2024-07-26T12:44:47+00:00"
+ "time": "2024-09-19T21:48:23+00:00"
},
{
"name": "symfony/service-contracts",
@@ -6680,16 +6690,16 @@
},
{
"name": "symfony/string",
- "version": "v7.1.4",
+ "version": "v7.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b"
+ "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/6cd670a6d968eaeb1c77c2e76091c45c56bc367b",
- "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b",
+ "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306",
+ "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306",
"shasum": ""
},
"require": {
@@ -6747,7 +6757,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.1.4"
+ "source": "https://github.com/symfony/string/tree/v7.1.5"
},
"funding": [
{
@@ -6763,7 +6773,7 @@
"type": "tidelift"
}
],
- "time": "2024-08-12T09:59:40+00:00"
+ "time": "2024-09-20T08:28:38+00:00"
},
{
"name": "textalk/websocket",
diff --git a/docker-compose.yml b/docker-compose.yml
index 6ecb0ecff8..479ca38b8f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -863,7 +863,7 @@ services:
appwrite-assistant:
container_name: appwrite-assistant
- image: appwrite/assistant:0.4.0
+ image: appwrite/assistant:0.5.0
networks:
- appwrite
environment:
diff --git a/src/Appwrite/Event/Func.php b/src/Appwrite/Event/Func.php
index 0cbaf17b60..4dad5802f7 100644
--- a/src/Appwrite/Event/Func.php
+++ b/src/Appwrite/Event/Func.php
@@ -8,6 +8,8 @@ use Utopia\Queue\Connection;
class Func extends Event
{
+ public const TYPE_ASYNC_WRITE = 'async_write';
+
protected string $jwt = '';
protected string $type = '';
protected string $body = '';
diff --git a/src/Appwrite/Event/Migration.php b/src/Appwrite/Event/Migration.php
index 478291829b..e57ac3c87c 100644
--- a/src/Appwrite/Event/Migration.php
+++ b/src/Appwrite/Event/Migration.php
@@ -81,7 +81,7 @@ class Migration extends Event
return $client->enqueue([
'project' => $this->project,
'user' => $this->user,
- 'migration' => $this->migration
+ 'migration' => $this->migration,
]);
}
}
diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php
index d25332126c..54bf6d96ea 100644
--- a/src/Appwrite/Extend/Exception.php
+++ b/src/Appwrite/Extend/Exception.php
@@ -39,6 +39,7 @@ class Exception extends \Exception
public const GENERAL_UNKNOWN = 'general_unknown';
public const GENERAL_MOCK = 'general_mock';
public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden';
+ public const GENERAL_RESOURCE_BLOCKED = 'general_resource_blocked';
public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin';
public const GENERAL_API_DISABLED = 'general_api_disabled';
public const GENERAL_SERVICE_DISABLED = 'general_service_disabled';
diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php
index 36b246b28b..d8f1d7da09 100644
--- a/src/Appwrite/GraphQL/Types/Mapper.php
+++ b/src/Appwrite/GraphQL/Types/Mapper.php
@@ -50,6 +50,7 @@ class Mapper
$defaults = [
'boolean' => Type::boolean(),
'string' => Type::string(),
+ 'payload' => Type::string(),
'integer' => Type::int(),
'double' => Type::float(),
'datetime' => Type::string(),
diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php
index 55d8db2924..c437d4d487 100644
--- a/src/Appwrite/Messaging/Adapter/Realtime.php
+++ b/src/Appwrite/Messaging/Adapter/Realtime.php
@@ -243,7 +243,11 @@ class Realtime extends Adapter
* @param string $event
* @param Document $payload
* @param Document|null $project
+ * @param Document|null $database
+ * @param Document|null $collection
+ * @param Document|null $bucket
* @return array
+ * @throws \Exception
*/
public static function fromPayload(string $event, Document $payload, Document $project = null, Document $database = null, Document $collection = null, Document $bucket = null): array
{
@@ -262,6 +266,13 @@ class Realtime extends Adapter
break;
case 'rules':
$channels[] = 'console';
+ $channels[] = 'projects.' . $project->getId();
+ $projectId = 'console';
+ $roles = [Role::team($project->getAttribute('teamId'))->toString()];
+ break;
+ case 'projects':
+ $channels[] = 'console';
+ $channels[] = 'projects.' . $parts[1];
$projectId = 'console';
$roles = [Role::team($project->getAttribute('teamId'))->toString()];
break;
@@ -280,6 +291,7 @@ class Realtime extends Adapter
case 'databases':
if (in_array($parts[4] ?? [], ['attributes', 'indexes'])) {
$channels[] = 'console';
+ $channels[] = 'projects.' . $project->getId();
$projectId = 'console';
$roles = [Role::team($project->getAttribute('teamId'))->toString()];
} elseif (($parts[4] ?? '') === 'documents') {
@@ -319,6 +331,7 @@ class Realtime extends Adapter
if ($parts[2] === 'executions') {
if (!empty($payload->getRead())) {
$channels[] = 'console';
+ $channels[] = 'projects.' . $project->getId();
$channels[] = 'executions';
$channels[] = 'executions.' . $payload->getId();
$channels[] = 'functions.' . $payload->getAttribute('functionId');
@@ -326,6 +339,7 @@ class Realtime extends Adapter
}
} elseif ($parts[2] === 'deployments') {
$channels[] = 'console';
+ $channels[] = 'projects.' . $project->getId();
$projectId = 'console';
$roles = [Role::team($project->getAttribute('teamId'))->toString()];
}
@@ -333,6 +347,7 @@ class Realtime extends Adapter
break;
case 'migrations':
$channels[] = 'console';
+ $channels[] = 'projects.' . $project->getId();
$projectId = 'console';
$roles = [Role::team($project->getAttribute('teamId'))->toString()];
break;
diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php
index 1da8a58ebe..afb38f35fc 100644
--- a/src/Appwrite/Platform/Tasks/Maintenance.php
+++ b/src/Appwrite/Platform/Tasks/Maintenance.php
@@ -49,12 +49,7 @@ class Maintenance extends Action
$this->foreachProject($dbForConsole, function (Document $project) use ($queueForDeletes, $usageStatsRetentionHourly) {
$queueForDeletes->setProject($project);
- $this->notifyDeleteTargets($queueForDeletes);
- $this->notifyDeleteExecutionLogs($queueForDeletes);
- $this->notifyDeleteAbuseLogs($queueForDeletes);
- $this->notifyDeleteAuditLogs($queueForDeletes);
- $this->notifyDeleteUsageStats($usageStatsRetentionHourly, $queueForDeletes);
- $this->notifyDeleteExpiredSessions($queueForDeletes);
+ $this->notifyProjects($queueForDeletes, $usageStatsRetentionHourly);
});
$this->notifyDeleteConnections($queueForDeletes);
@@ -64,6 +59,19 @@ class Maintenance extends Action
}, $interval, $delay);
}
+ /**
+ * Hook to allow sub-classes to extend project-level maintenance functionality.
+ */
+ protected function notifyProjects(Delete $queueForDeletes, int $usageStatsRetentionHourly): void
+ {
+ $this->notifyDeleteTargets($queueForDeletes);
+ $this->notifyDeleteExecutionLogs($queueForDeletes);
+ $this->notifyDeleteAbuseLogs($queueForDeletes);
+ $this->notifyDeleteAuditLogs($queueForDeletes);
+ $this->notifyDeleteUsageStats($usageStatsRetentionHourly, $queueForDeletes);
+ $this->notifyDeleteExpiredSessions($queueForDeletes);
+ }
+
protected function foreachProject(Database $dbForConsole, callable $callback): void
{
// TODO: @Meldiron name of this method no longer matches. It does not delete, and it gives whole document
diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php
index 79a05dcd13..a1b85c341f 100644
--- a/src/Appwrite/Platform/Tasks/ScheduleBase.php
+++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php
@@ -24,11 +24,8 @@ abstract class ScheduleBase extends Action
abstract public static function getName(): string;
abstract public static function getSupportedResource(): string;
-
- abstract protected function enqueueResources(
- Group $pools,
- Database $dbForConsole
- );
+ abstract public static function getCollectionId(): string;
+ abstract protected function enqueueResources(Group $pools, Database $dbForConsole, callable $getProjectDB): void;
public function __construct()
{
@@ -62,14 +59,8 @@ abstract class ScheduleBase extends Action
$getSchedule = function (Document $schedule) use ($dbForConsole, $getProjectDB): array {
$project = $dbForConsole->getDocument('projects', $schedule->getAttribute('projectId'));
- $collectionId = match ($schedule->getAttribute('resourceType')) {
- 'function' => 'functions',
- 'message' => 'messages',
- 'execution' => 'executions'
- };
-
$resource = $getProjectDB($project)->getDocument(
- $collectionId,
+ static::getCollectionId(),
$schedule->getAttribute('resourceId')
);
@@ -113,12 +104,7 @@ abstract class ScheduleBase extends Action
try {
$this->schedules[$document->getInternalId()] = $getSchedule($document);
} catch (\Throwable $th) {
- $collectionId = match ($document->getAttribute('resourceType')) {
- 'function' => 'functions',
- 'message' => 'messages',
- 'execution' => 'executions'
- };
-
+ $collectionId = static::getCollectionId();
Console::error("Failed to load schedule for project {$document['projectId']} {$collectionId} {$document['resourceId']}");
Console::error($th->getMessage());
}
@@ -133,7 +119,7 @@ abstract class ScheduleBase extends Action
Console::success("Starting timers at " . DateTime::now());
- run(function () use ($dbForConsole, &$lastSyncUpdate, $getSchedule, $pools) {
+ run(function () use ($dbForConsole, &$lastSyncUpdate, $getSchedule, $pools, $getProjectDB) {
/**
* The timer synchronize $schedules copy with database collection.
*/
@@ -172,10 +158,10 @@ abstract class ScheduleBase extends Action
$new = \strtotime($document['resourceUpdatedAt']);
if (!$document['active']) {
- Console::info("Removing: {$document['resourceId']}");
+ Console::info("Removing: {$document['resourceType']}::{$document['resourceId']}");
unset($this->schedules[$document->getInternalId()]);
} elseif ($new !== $org) {
- Console::info("Updating: {$document['resourceId']}");
+ Console::info("Updating: {$document['resourceType']}::{$document['resourceId']}");
$this->schedules[$document->getInternalId()] = $getSchedule($document);
}
}
@@ -193,10 +179,10 @@ abstract class ScheduleBase extends Action
Timer::tick(
static::ENQUEUE_TIMER * 1000,
- fn () => $this->enqueueResources($pools, $dbForConsole)
+ fn () => $this->enqueueResources($pools, $dbForConsole, $getProjectDB)
);
- $this->enqueueResources($pools, $dbForConsole);
+ $this->enqueueResources($pools, $dbForConsole, $getProjectDB);
});
}
}
diff --git a/src/Appwrite/Platform/Tasks/ScheduleExecutions.php b/src/Appwrite/Platform/Tasks/ScheduleExecutions.php
index 682d796585..73a2814397 100644
--- a/src/Appwrite/Platform/Tasks/ScheduleExecutions.php
+++ b/src/Appwrite/Platform/Tasks/ScheduleExecutions.php
@@ -22,7 +22,12 @@ class ScheduleExecutions extends ScheduleBase
return 'execution';
}
- protected function enqueueResources(Group $pools, Database $dbForConsole): void
+ public static function getCollectionId(): string
+ {
+ return 'executions';
+ }
+
+ protected function enqueueResources(Group $pools, Database $dbForConsole, callable $getProjectDB): void
{
$queue = $pools->get('queue')->pop();
$connection = $queue->getResource();
diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php
index e2c278714f..4d57902330 100644
--- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php
+++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php
@@ -26,7 +26,12 @@ class ScheduleFunctions extends ScheduleBase
return 'function';
}
- protected function enqueueResources(Group $pools, Database $dbForConsole): void
+ public static function getCollectionId(): string
+ {
+ return 'functions';
+ }
+
+ protected function enqueueResources(Group $pools, Database $dbForConsole, callable $getProjectDB): void
{
$timerStart = \microtime(true);
$time = DateTime::now();
diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php
index 167f1282ed..b9d8e2a282 100644
--- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php
+++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php
@@ -21,7 +21,12 @@ class ScheduleMessages extends ScheduleBase
return 'message';
}
- protected function enqueueResources(Group $pools, Database $dbForConsole): void
+ public static function getCollectionId(): string
+ {
+ return 'messages';
+ }
+
+ protected function enqueueResources(Group $pools, Database $dbForConsole, callable $getProjectDB): void
{
foreach ($this->schedules as $schedule) {
if (!$schedule['active']) {
diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php
index e171f2f405..f71de98d95 100644
--- a/src/Appwrite/Platform/Tasks/Specs.php
+++ b/src/Appwrite/Platform/Tasks/Specs.php
@@ -5,9 +5,11 @@ namespace Appwrite\Platform\Tasks;
use Appwrite\Specification\Format\OpenAPI3;
use Appwrite\Specification\Format\Swagger2;
use Appwrite\Specification\Specification;
-use Appwrite\Utopia\Response;
+use Appwrite\Utopia\Request as AppwriteRequest;
+use Appwrite\Utopia\Response as AppwriteResponse;
use Exception;
-use Swoole\Http\Response as HttpResponse;
+use Swoole\Http\Request as SwooleRequest;
+use Swoole\Http\Response as SwooleResponse;
use Utopia\App;
use Utopia\Cache\Adapter\None;
use Utopia\Cache\Cache;
@@ -17,7 +19,8 @@ use Utopia\Database\Adapter\MySQL;
use Utopia\Database\Database;
use Utopia\Platform\Action;
use Utopia\Registry\Registry;
-use Utopia\Request;
+use Utopia\Request as UtopiaRequest;
+use Utopia\Response as UtopiaResponse;
use Utopia\System\System;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
@@ -29,6 +32,16 @@ class Specs extends Action
return 'specs';
}
+ public function getRequest(): UtopiaRequest
+ {
+ return new AppwriteRequest(new SwooleRequest());
+ }
+
+ public function getResponse(): UtopiaResponse
+ {
+ return new AppwriteResponse(new SwooleResponse());
+ }
+
public function __construct()
{
$this
@@ -42,11 +55,11 @@ class Specs extends Action
public function action(string $version, string $mode, Registry $register): void
{
$appRoutes = App::getRoutes();
- $response = new Response(new HttpResponse());
+ $response = $this->getResponse();
$mocks = ($mode === 'mocks');
// Mock dependencies
- App::setResource('request', fn () => new Request());
+ App::setResource('request', fn () => $this->getRequest());
App::setResource('response', fn () => $response);
App::setResource('dbForConsole', fn () => new Database(new MySQL(''), new Cache(new None())));
App::setResource('dbForProject', fn () => new Database(new MySQL(''), new Cache(new None())));
@@ -183,10 +196,8 @@ class Specs extends Action
case APP_AUTH_TYPE_SESSION:
$sdkPlatforms[] = APP_PLATFORM_CLIENT;
break;
- case APP_AUTH_TYPE_KEY:
- $sdkPlatforms[] = APP_PLATFORM_SERVER;
- break;
case APP_AUTH_TYPE_JWT:
+ case APP_AUTH_TYPE_KEY:
$sdkPlatforms[] = APP_PLATFORM_SERVER;
break;
case APP_AUTH_TYPE_ADMIN:
diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php
index 56f5f012e8..f697e7be13 100644
--- a/src/Appwrite/Platform/Workers/Databases.php
+++ b/src/Appwrite/Platform/Workers/Databases.php
@@ -5,7 +5,6 @@ namespace Appwrite\Platform\Workers;
use Appwrite\Event\Event;
use Appwrite\Messaging\Adapter\Realtime;
use Exception;
-use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -492,8 +491,6 @@ class Databases extends Action
});
$dbForProject->deleteCollection('database_' . $database->getInternalId());
-
- $this->deleteAuditLogsByResource('database/' . $database->getId(), $project, $dbForProject);
}
/**
@@ -549,23 +546,8 @@ class Databases extends Action
Query::equal('databaseInternalId', [$databaseInternalId]),
Query::equal('collectionInternalId', [$collectionInternalId])
], $dbForProject);
-
- $this->deleteAuditLogsByResource('database/' . $databaseId . '/collection/' . $collectionId, $project, $dbForProject);
}
- /**
- * @param string $resource
- * @param Document $project
- * @param Database $dbForProject
- * @return void
- * @throws Exception
- */
- protected function deleteAuditLogsByResource(string $resource, Document $project, Database $dbForProject): void
- {
- $this->deleteByGroup(Audit::COLLECTION, [
- Query::equal('resource', [$resource])
- ], $dbForProject);
- }
/**
* @param string $collection collectionID
diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php
index c70d9ca11b..48e4014f1e 100644
--- a/src/Appwrite/Platform/Workers/Deletes.php
+++ b/src/Appwrite/Platform/Workers/Deletes.php
@@ -119,10 +119,6 @@ class Deletes extends Action
if (!$project->isEmpty()) {
$this->deleteAuditLogs($project, $getProjectDB, $auditRetention);
}
-
- if (!$document->isEmpty()) {
- $this->deleteAuditLogsByResource($getProjectDB, 'document/' . $document->getId(), $project);
- }
break;
case DELETE_TYPE_ABUSE:
$this->deleteAbuseLogs($project, $getProjectDB, $abuseRetention);
@@ -480,6 +476,7 @@ class Deletes extends Action
private function deleteProject(Database $dbForConsole, callable $getProjectDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, Document $document): void
{
$projectInternalId = $document->getInternalId();
+ $projectId = $document->getId();
try {
$dsn = new DSN($document->getAttribute('database', 'console'));
@@ -503,7 +500,18 @@ class Deletes extends Action
foreach ($collections as $collection) {
if ($dsn->getHost() !== System::getEnv('_APP_DATABASE_SHARED_TABLES', '') || !\in_array($collection->getId(), $projectCollectionIds)) {
- $dbForProject->deleteCollection($collection->getId());
+ try {
+ $dbForProject->deleteCollection($collection->getId());
+ } catch (Throwable $e) {
+ Console::error('Error deleting '.$collection->getId().' '.$e->getMessage());
+
+ /**
+ * Ignore junction tables;
+ */
+ if (!preg_match('/^_\d+_\d+$/', $collection->getId())) {
+ throw $e;
+ }
+ }
} else {
$this->deleteByGroup($collection->getId(), [], database: $dbForProject);
}
@@ -557,6 +565,11 @@ class Deletes extends Action
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
+ // Delete Schedules (No projectInternalId in this collection)
+ $this->deleteByGroup('schedules', [
+ Query::equal('projectId', [$projectId]),
+ ], $dbForConsole);
+
// Delete metadata table
if ($dsn->getHost() !== System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$dbForProject->deleteCollection('_metadata');
@@ -716,22 +729,6 @@ class Deletes extends Action
}
}
- /**
- * @param callable $getProjectDB
- * @param string $resource
- * @param Document $project
- * @return void
- * @throws Exception
- */
- private function deleteAuditLogsByResource(callable $getProjectDB, string $resource, Document $project): void
- {
- $dbForProject = $getProjectDB($project);
-
- $this->deleteByGroup(Audit::COLLECTION, [
- Query::equal('resource', [$resource])
- ], $dbForProject);
- }
-
/**
* @param callable $getProjectDB
* @param Device $deviceForFunctions
@@ -955,7 +952,7 @@ class Deletes extends Action
* @return void
* @throws Exception
*/
- private function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
+ protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
{
$count = 0;
$chunk = 0;
@@ -997,7 +994,7 @@ class Deletes extends Action
* @return void
* @throws Exception
*/
- private function listByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
+ protected function listByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
{
$count = 0;
$chunk = 0;
diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php
index e60f67416d..3dc3e65eee 100644
--- a/src/Appwrite/Platform/Workers/Functions.php
+++ b/src/Appwrite/Platform/Workers/Functions.php
@@ -41,29 +41,33 @@ class Functions extends Action
$this
->desc('Functions worker')
->groups(['functions'])
+ ->inject('project')
->inject('message')
->inject('dbForProject')
->inject('queueForFunctions')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('log')
- ->callback(fn (Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log) => $this->action($message, $dbForProject, $queueForFunctions, $queueForEvents, $queueForUsage, $log));
+ ->inject('isResourceBlocked')
+ ->callback(fn (Document $project, Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log, callable $isResourceBlocked) => $this->action($project, $message, $dbForProject, $queueForFunctions, $queueForEvents, $queueForUsage, $log, $isResourceBlocked));
}
/**
+ * @param Document $project
* @param Message $message
* @param Database $dbForProject
* @param Func $queueForFunctions
* @param Event $queueForEvents
* @param Usage $queueForUsage
* @param Log $log
+ * @param callable $isResourceBlocked
* @return void
* @throws Authorization
* @throws Structure
* @throws \Utopia\Database\Exception
* @throws Conflict
*/
- public function action(Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log): void
+ public function action(Document $project, Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log, callable $isResourceBlocked): void
{
$payload = $message->getPayload() ?? [];
@@ -72,48 +76,22 @@ class Functions extends Action
}
$type = $payload['type'] ?? '';
- $events = $payload['events'] ?? [];
- $data = $payload['body'] ?? '';
- $eventData = $payload['payload'] ?? '';
- $project = new Document($payload['project'] ?? []);
- $function = new Document($payload['function'] ?? []);
- $functionId = $payload['functionId'] ?? '';
- $user = new Document($payload['user'] ?? []);
- $userId = $payload['userId'] ?? '';
- $method = $payload['method'] ?? 'POST';
- $headers = $payload['headers'] ?? [];
- $path = $payload['path'] ?? '/';
- $jwt = $payload['jwt'] ?? '';
- if ($user->isEmpty() && !empty($userId)) {
- $user = $dbForProject->getDocument('users', $userId);
- }
-
- if (empty($jwt) && !$user->isEmpty()) {
- $jwtExpiry = $function->getAttribute('timeout', 900);
- $jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $jwtExpiry, 0);
- $jwt = $jwtObj->encode([
- 'userId' => $user->getId(),
- ]);
- }
-
- if ($project->getId() === 'console') {
+ // Short-term solution to offhand write operation from API container
+ if ($type === Func::TYPE_ASYNC_WRITE) {
+ $execution = new Document($payload['execution'] ?? []);
+ $dbForProject->createDocument('executions', $execution);
return;
}
- if ($function->isEmpty() && !empty($functionId)) {
- $function = $dbForProject->getDocument('functions', $functionId);
- }
-
- $log->addTag('functionId', $function->getId());
- $log->addTag('projectId', $project->getId());
- $log->addTag('type', $type);
+ $eventData = $payload['payload'] ?? '';
+ $user = new Document($payload['user'] ?? []);
+ $events = $payload['events'] ?? [];
if (!empty($events)) {
$limit = 30;
$sum = 30;
$offset = 0;
- /** @var Document[] $functions */
while ($sum >= $limit) {
$functions = $dbForProject->find('functions', [
Query::limit($limit),
@@ -130,6 +108,12 @@ class Functions extends Action
if (!array_intersect($events, $function->getAttribute('events', []))) {
continue;
}
+
+ if ($isResourceBlocked($project, 'functions', $function->getId())) {
+ Console::log('Function ' . $function->getId() . ' is blocked, skipping execution.');
+ continue;
+ }
+
Console::success('Iterating function: ' . $function->getAttribute('name'));
$this->execute(
@@ -160,6 +144,50 @@ class Functions extends Action
return;
}
+ $data = $payload['body'] ?? '';
+ $function = new Document($payload['function'] ?? []);
+ $functionId = $payload['functionId'] ?? '';
+ $userId = $payload['userId'] ?? '';
+ $method = $payload['method'] ?? 'POST';
+ $headers = $payload['headers'] ?? [];
+ $path = $payload['path'] ?? '/';
+ $jwt = $payload['jwt'] ?? '';
+
+ if ($user->isEmpty() && !empty($userId)) {
+ $user = $dbForProject->getDocument('users', $userId);
+ }
+
+ if (empty($jwt) && !$user->isEmpty()) {
+ $jwtExpiry = $function->getAttribute('timeout', 900);
+ $jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $jwtExpiry, 0);
+ $jwt = $jwtObj->encode([
+ 'userId' => $user->getId(),
+ ]);
+ }
+
+ if ($project->getId() === 'console') {
+ return;
+ }
+
+ if ($function->isEmpty() && !empty($functionId)) {
+ $function = $dbForProject->getDocument('functions', $functionId);
+ }
+
+ // $function still empty, we can't execute this
+ if ($function->isEmpty()) {
+ Console::warning('Got empty function without functionId.');
+ return;
+ }
+
+ if ($isResourceBlocked($project, 'functions', $function->getId())) {
+ Console::log('Function ' . $function->getId() . ' is blocked, skipping execution.');
+ return;
+ }
+
+ $log->addTag('functionId', $function->getId());
+ $log->addTag('projectId', $project->getId());
+ $log->addTag('type', $type);
+
/**
* Handle Schedule and HTTP execution.
*/
@@ -587,7 +615,8 @@ class Functions extends Action
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
event: $allEvents[0],
- payload: $execution
+ payload: $execution,
+ project: $project
);
Realtime::send(
projectId: 'console',
diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php
index b0f05522fa..510fec0431 100644
--- a/src/Appwrite/Platform/Workers/Messaging.php
+++ b/src/Appwrite/Platform/Workers/Messaging.php
@@ -489,11 +489,29 @@ class Messaging extends Action
return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'),
- 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken'], null, isset($credentials['messagingServiceSid']) ? $credentials['messagingServiceSid'] : null),
- 'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']),
- 'telesign' => new Telesign($credentials['customerId'], $credentials['apiKey']),
- 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey'], $credentials['templateId']),
- 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']),
+ 'twilio' => new Twilio(
+ $credentials['accountSid'] ?? '',
+ $credentials['authToken'] ?? '',
+ null,
+ $credentials['messagingServiceSid'] ?? null
+ ),
+ 'textmagic' => new TextMagic(
+ $credentials['username'] ?? '',
+ $credentials['apiKey'] ?? ''
+ ),
+ 'telesign' => new Telesign(
+ $credentials['customerId'] ?? '',
+ $credentials['apiKey'] ?? ''
+ ),
+ 'msg91' => new Msg91(
+ $credentials['senderId'] ?? '',
+ $credentials['authKey'] ?? '',
+ $credentials['templateId'] ?? ''
+ ),
+ 'vonage' => new Vonage(
+ $credentials['apiKey'] ?? '',
+ $credentials['apiSecret'] ?? ''
+ ),
default => null
};
}
@@ -506,11 +524,11 @@ class Messaging extends Action
return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'),
'apns' => new APNS(
- $credentials['authKey'],
- $credentials['authKeyId'],
- $credentials['teamId'],
- $credentials['bundleId'],
- $options['sandbox']
+ $credentials['authKey'] ?? '',
+ $credentials['authKeyId'] ?? '',
+ $credentials['teamId'] ?? '',
+ $credentials['bundleId'] ?? '',
+ $options['sandbox'] ?? false
),
'fcm' => new FCM(\json_encode($credentials['serviceAccountJSON'])),
default => null
@@ -521,24 +539,25 @@ class Messaging extends Action
{
$credentials = $provider->getAttribute('credentials', []);
$options = $provider->getAttribute('options', []);
+ $apiKey = $credentials['apiKey'] ?? '';
return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'),
'smtp' => new SMTP(
- $credentials['host'],
- $credentials['port'],
- $credentials['username'],
- $credentials['password'],
- $options['encryption'],
- $options['autoTLS'],
- $options['mailer'],
+ $credentials['host'] ?? '',
+ $credentials['port'] ?? 25,
+ $credentials['username'] ?? '',
+ $credentials['password'] ?? '',
+ $options['encryption'] ?? '',
+ $options['autoTLS'] ?? false,
+ $options['mailer'] ?? '',
),
'mailgun' => new Mailgun(
- $credentials['apiKey'],
- $credentials['domain'],
- $credentials['isEuRegion']
+ $apiKey,
+ $credentials['domain'] ?? '',
+ $credentials['isEuRegion'] ?? false
),
- 'sendgrid' => new Sendgrid($credentials['apiKey']),
+ 'sendgrid' => new Sendgrid($apiKey),
default => null
};
}
diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php
index 8ab5ebac46..beff0b064b 100644
--- a/src/Appwrite/Platform/Workers/Migrations.php
+++ b/src/Appwrite/Platform/Workers/Migrations.php
@@ -8,6 +8,7 @@ use Appwrite\Permission;
use Appwrite\Role;
use Exception;
use Utopia\CLI\Console;
+use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization;
@@ -16,11 +17,11 @@ use Utopia\Database\Exception\Restricted;
use Utopia\Database\Exception\Structure;
use Utopia\Database\Helpers\ID;
use Utopia\Logger\Log;
-use Utopia\Logger\Log\Breadcrumb;
-use Utopia\Migration\Destinations\Appwrite as DestinationsAppwrite;
+use Utopia\Migration\Destination;
+use Utopia\Migration\Destinations\Appwrite as DestinationAppwrite;
use Utopia\Migration\Exception as MigrationException;
use Utopia\Migration\Source;
-use Utopia\Migration\Sources\Appwrite;
+use Utopia\Migration\Sources\Appwrite as SourceAppwrite;
use Utopia\Migration\Sources\Firebase;
use Utopia\Migration\Sources\NHost;
use Utopia\Migration\Sources\Supabase;
@@ -30,8 +31,11 @@ use Utopia\Queue\Message;
class Migrations extends Action
{
- private ?Database $dbForProject = null;
- private ?Database $dbForConsole = null;
+ protected Database $dbForProject;
+
+ protected Database $dbForConsole;
+
+ protected Document $project;
public static function getName(): string
{
@@ -53,11 +57,6 @@ class Migrations extends Action
}
/**
- * @param Message $message
- * @param Database $dbForProject
- * @param Database $dbForConsole
- * @param Log $log
- * @return void
* @throws Exception
*/
public function action(Message $message, Database $dbForProject, Database $dbForConsole, Log $log): void
@@ -78,6 +77,7 @@ class Migrations extends Action
$this->dbForProject = $dbForProject;
$this->dbForConsole = $dbForConsole;
+ $this->project = $project;
/**
* Handle Event execution.
@@ -89,17 +89,17 @@ class Migrations extends Action
$log->addTag('migrationId', $migration->getId());
$log->addTag('projectId', $project->getId());
- $this->processMigration($project, $migration, $log);
+ $this->processMigration($migration, $log);
}
/**
- * @param string $source
- * @param array $credentials
- * @return Source
* @throws Exception
*/
- protected function processSource(string $source, array $credentials): Source
+ protected function processSource(Document $migration): Source
{
+ $source = $migration->getAttribute('source');
+ $credentials = $migration->getAttribute('credentials');
+
return match ($source) {
Firebase::getName() => new Firebase(
json_decode($credentials['serviceAccount'], true),
@@ -122,11 +122,35 @@ class Migrations extends Action
$credentials['password'],
$credentials['port'],
),
- Appwrite::getName() => new Appwrite($credentials['projectId'], str_starts_with($credentials['endpoint'], 'http://localhost/v1') ? 'http://appwrite/v1' : $credentials['endpoint'], $credentials['apiKey']),
+ SourceAppwrite::getName() => new SourceAppwrite(
+ $credentials['projectId'],
+ $credentials['endpoint'],
+ $credentials['apiKey'],
+ ),
default => throw new \Exception('Invalid source type'),
};
}
+ /**
+ * @throws Exception
+ */
+ protected function processDestination(Document $migration): Destination
+ {
+ $destination = $migration->getAttribute('destination');
+ $credentials = $migration->getAttribute('credentials');
+
+ return match ($destination) {
+ DestinationAppwrite::getName() => new DestinationAppwrite(
+ $credentials['projectId'],
+ $credentials['endpoint'],
+ $credentials['apiKey'],
+ $this->dbForProject,
+ Config::getParam('collections', [])['databases']['collections'],
+ ),
+ default => throw new \Exception('Invalid destination type'),
+ };
+ }
+
/**
* @throws Authorization
* @throws Structure
@@ -167,8 +191,6 @@ class Migrations extends Action
}
/**
- * @param Document $apiKey
- * @return void
* @throws \Utopia\Database\Exception
* @throws Authorization
* @throws Conflict
@@ -181,8 +203,6 @@ class Migrations extends Action
}
/**
- * @param Document $project
- * @return Document
* @throws Authorization
* @throws Structure
* @throws \Utopia\Database\Exception
@@ -233,99 +253,116 @@ class Migrations extends Action
}
/**
- * @param Document $project
- * @param Document $migration
- * @param Log $log
- * @return void
* @throws Authorization
* @throws Conflict
* @throws Restricted
* @throws Structure
* @throws \Utopia\Database\Exception
+ * @throws Exception
*/
- protected function processMigration(Document $project, Document $migration, Log $log): void
+ protected function processMigration(Document $migration, Log $log): void
{
- /**
- * @var Document $migrationDocument
- * @var Transfer $transfer
- */
- $migrationDocument = null;
- $transfer = null;
+ $project = $this->project;
$projectDocument = $this->dbForConsole->getDocument('projects', $project->getId());
$tempAPIKey = $this->generateAPIKey($projectDocument);
+ $transfer = $source = $destination = null;
+
try {
- $migrationDocument = $this->dbForProject->getDocument('migrations', $migration->getId());
- $migrationDocument->setAttribute('stage', 'processing');
- $migrationDocument->setAttribute('status', 'processing');
- $log->addBreadcrumb(new Breadcrumb("debug", "migration", "Migration hit stage 'processing'", \microtime(true)));
- $this->updateMigrationDocument($migrationDocument, $projectDocument);
+ $migration = $this->dbForProject->getDocument('migrations', $migration->getId());
- $log->addTag('type', $migrationDocument->getAttribute('source'));
+ if (
+ $migration->getAttribute('source') === SourceAppwrite::getName() ||
+ $migration->getAttribute('destination') === DestinationAppwrite::getName()
+ ) {
+ $credentials = $migration->getAttribute('credentials', []);
- $source = $this->processSource($migrationDocument->getAttribute('source'), $migrationDocument->getAttribute('credentials'));
+ $credentials['projectId'] = $credentials['projectId'] ?? $projectDocument->getId();
+ $credentials['endpoint'] = $credentials['endpoint'] ?? 'http://appwrite/v1';
+ $credentials['apiKey'] = $credentials['apiKey'] ?? $tempAPIKey['secret'];
+
+ $migration->setAttribute('credentials', $credentials);
+ }
+
+ $migration->setAttribute('stage', 'processing');
+ $migration->setAttribute('status', 'processing');
+ $this->updateMigrationDocument($migration, $projectDocument);
+
+ $log->addTag('type', $migration->getAttribute('source'));
+
+ $source = $this->processSource($migration);
+ $destination = $this->processDestination($migration);
$source->report();
- $destination = new DestinationsAppwrite(
- $projectDocument->getId(),
- 'http://appwrite/v1',
- $tempAPIKey['secret'],
- );
-
$transfer = new Transfer(
$source,
$destination
);
/** Start Transfer */
- $migrationDocument->setAttribute('stage', 'migrating');
- $log->addBreadcrumb(new Breadcrumb("debug", "migration", "Migration hit stage 'migrating'", \microtime(true)));
- $this->updateMigrationDocument($migrationDocument, $projectDocument);
- $transfer->run($migrationDocument->getAttribute('resources'), function () use ($migrationDocument, $transfer, $projectDocument) {
- $migrationDocument->setAttribute('resourceData', json_encode($transfer->getCache()));
- $migrationDocument->setAttribute('statusCounters', json_encode($transfer->getStatusCounters()));
+ $migration->setAttribute('stage', 'migrating');
+ $this->updateMigrationDocument($migration, $projectDocument);
- $this->updateMigrationDocument($migrationDocument, $projectDocument);
- });
+ $transfer->run(
+ $migration->getAttribute('resources'),
+ function () use ($migration, $transfer, $projectDocument) {
+ $migration->setAttribute('resourceData', json_encode($transfer->getCache()));
+ $migration->setAttribute('statusCounters', json_encode($transfer->getStatusCounters()));
+ $this->updateMigrationDocument($migration, $projectDocument);
+ },
+ $migration->getAttribute('resourceId'),
+ $migration->getAttribute('resourceType')
+ );
+
+ $destination->shutDown();
+ $source->shutDown();
$sourceErrors = $source->getErrors();
$destinationErrors = $destination->getErrors();
- if (!empty($sourceErrors) || !empty($destinationErrors)) {
- $migrationDocument->setAttribute('status', 'failed');
- $migrationDocument->setAttribute('stage', 'finished');
- $log->addBreadcrumb(new Breadcrumb("debug", "migration", "Migration hit stage 'finished' and failed", \microtime(true)));
+ if (! empty($sourceErrors) || ! empty($destinationErrors)) {
+ $migration->setAttribute('status', 'failed');
+ $migration->setAttribute('stage', 'finished');
$errorMessages = [];
foreach ($sourceErrors as $error) {
- /** @var MigrationException $error */
- $errorMessages[] = "Error occurred while fetching '{$error->getResourceGroup()}:{$error->getResourceId()}' from source with message: '{$error->getMessage()}'";
+ /** @var $sourceErrors $error */
+ $message = "Error occurred while fetching '{$error->getResourceName()}:{$error->getResourceId()}' from source with message: '{$error->getMessage()}'";
+ if ($error->getPrevious()) {
+ $message .= " Message: ".$error->getPrevious()->getMessage() . " File: ".$error->getPrevious()->getFile() . " Line: ".$error->getPrevious()->getLine();
+ }
+
+ $errorMessages[] = $message;
}
foreach ($destinationErrors as $error) {
+ $message = "Error occurred while pushing '{$error->getResourceName()}:{$error->getResourceId()}' to destination with message: '{$error->getMessage()}'";
+
+ if ($error->getPrevious()) {
+ $message .= " Message: ".$error->getPrevious()->getMessage() . " File: ".$error->getPrevious()->getFile() . " Line: ".$error->getPrevious()->getLine();
+ }
+
/** @var MigrationException $error */
- $errorMessages[] = "Error occurred while pushing '{$error->getResourceGroup()}:{$error->getResourceId()}' to destination with message: '{$error->getMessage()}'";
+ $errorMessages[] = $message;
}
- $migrationDocument->setAttribute('errors', $errorMessages);
+ $migration->setAttribute('errors', $errorMessages);
$log->addExtra('migrationErrors', json_encode($errorMessages));
- $this->updateMigrationDocument($migrationDocument, $projectDocument);
+ $this->updateMigrationDocument($migration, $projectDocument);
return;
}
- $migrationDocument->setAttribute('status', 'completed');
- $migrationDocument->setAttribute('stage', 'finished');
- $log->addBreadcrumb(new Breadcrumb("debug", "migration", "Migration hit stage 'finished' and succeeded", \microtime(true)));
+ $migration->setAttribute('status', 'completed');
+ $migration->setAttribute('stage', 'finished');
} catch (\Throwable $th) {
Console::error($th->getMessage());
+ Console::error($th->getTraceAsString());
- if ($migrationDocument) {
- Console::error($th->getMessage());
- Console::error($th->getTraceAsString());
- $migrationDocument->setAttribute('status', 'failed');
- $migrationDocument->setAttribute('stage', 'finished');
- $migrationDocument->setAttribute('errors', [$th->getMessage()]);
+ if (! $migration->isEmpty()) {
+ $migration->setAttribute('status', 'failed');
+ $migration->setAttribute('stage', 'finished');
+ $migration->setAttribute('errors', [$th->getMessage()]);
return;
}
@@ -337,26 +374,35 @@ class Migrations extends Action
$errorMessages = [];
foreach ($sourceErrors as $error) {
/** @var MigrationException $error */
- $errorMessages[] = "Error occurred while fetching '{$error->getResourceGroup()}:{$error->getResourceId()}' from source with message '{$error->getMessage()}'";
+ $errorMessages[] = "Error occurred while fetching '{$error->getResourceName()}:{$error->getResourceId()}' from source with message '{$error->getMessage()}'";
}
foreach ($destinationErrors as $error) {
/** @var MigrationException $error */
- $errorMessages[] = "Error occurred while pushing '{$error->getResourceGroup()}:{$error->getResourceId()}' to destination with message '{$error->getMessage()}'";
+ $errorMessages[] = "Error occurred while pushing '{$error->getResourceName()}:{$error->getResourceId()}' to destination with message '{$error->getMessage()}'";
}
- $migrationDocument->setAttribute('errors', $errorMessages);
+ $migration->setAttribute('errors', $errorMessages);
$log->addTag('migrationErrors', json_encode($errorMessages));
}
} finally {
- if ($tempAPIKey) {
+ if (! $tempAPIKey->isEmpty()) {
$this->removeAPIKey($tempAPIKey);
}
- if ($migrationDocument) {
- $this->updateMigrationDocument($migrationDocument, $projectDocument);
- if ($migrationDocument->getAttribute('status', '') == 'failed') {
- throw new Exception("Migration failed");
- }
+ $this->updateMigrationDocument($migration, $projectDocument);
+
+ if ($migration->getAttribute('status', '') === 'failed') {
+ Console::error('Migration('.$migration->getInternalId().':'.$migration->getId().') failed, Project('.$this->project->getInternalId().':'.$this->project->getId().')');
+
+ $destination->error();
+ $source->error();
+
+ throw new Exception('Migration failed');
+ }
+
+ if ($migration->getAttribute('status', '') === 'completed') {
+ $destination->success();
+ $source->success();
}
}
}
diff --git a/src/Appwrite/Platform/Workers/UsageDump.php b/src/Appwrite/Platform/Workers/UsageDump.php
index b7097dbb04..b5480e1dec 100644
--- a/src/Appwrite/Platform/Workers/UsageDump.php
+++ b/src/Appwrite/Platform/Workers/UsageDump.php
@@ -4,6 +4,7 @@ namespace Appwrite\Platform\Workers;
use Appwrite\Extend\Exception;
use Utopia\CLI\Console;
+use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate;
@@ -11,6 +12,10 @@ use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\System\System;
+const METRIC_COLLECTION_LEVEL_STORAGE = 4;
+const METRIC_DATABASE_LEVEL_STORAGE = 3;
+const METRIC_PROJECT_LEVEL_STORAGE = 2;
+
class UsageDump extends Action
{
protected array $stats = [];
@@ -70,6 +75,15 @@ class UsageDump extends Action
continue;
}
+ if (str_contains($key, METRIC_DATABASES_STORAGE)) {
+ try {
+ $this->handleDatabaseStorage($key, $dbForProject);
+ } catch (\Exception $e) {
+ console::error('[' . DateTime::now() . '] failed to calculate database storage for key [' . $key . '] ' . $e->getMessage());
+ }
+ continue;
+ }
+
foreach ($this->periods as $period => $format) {
$time = 'inf' === $period ? null : date($format, time());
$id = \md5("{$time}_{$period}_{$key}");
@@ -107,4 +121,162 @@ class UsageDump extends Action
}
}
}
+
+ private function handleDatabaseStorage(string $key, Database $dbForProject): void
+ {
+ $data = explode('.', $key);
+ $start = microtime(true);
+
+ $updateMetric = function (Database $dbForProject, int $value, string $key, string $period, string|null $time) {
+ $id = \md5("{$time}_{$period}_{$key}");
+
+ try {
+ $dbForProject->createDocument('stats', new Document([
+ '$id' => $id,
+ 'period' => $period,
+ 'time' => $time,
+ 'metric' => $key,
+ 'value' => $value,
+ 'region' => System::getEnv('_APP_REGION', 'default'),
+ ]));
+ } catch (Duplicate $th) {
+ if ($value < 0) {
+ $dbForProject->decreaseDocumentAttribute(
+ 'stats',
+ $id,
+ 'value',
+ abs($value)
+ );
+ } else {
+ $dbForProject->increaseDocumentAttribute(
+ 'stats',
+ $id,
+ 'value',
+ $value
+ );
+ }
+ }
+ };
+
+ foreach ($this->periods as $period => $format) {
+ $time = 'inf' === $period ? null : date($format, time());
+ $id = \md5("{$time}_{$period}_{$key}");
+
+ $value = 0;
+ $previousValue = 0;
+ try {
+ $previousValue = ($dbForProject->getDocument('stats', $id))->getAttribute('value', 0);
+ } catch (\Exception $e) {
+ // No previous value
+ }
+
+ switch (count($data)) {
+ // Collection Level
+ case METRIC_COLLECTION_LEVEL_STORAGE:
+ Console::log('[' . DateTime::now() . '] Collection Level Storage Calculation [' . $key . ']');
+ $databaseInternalId = $data[0];
+ $collectionInternalId = $data[1];
+
+ try {
+ $value = $dbForProject->getSizeOfCollection('database_' . $databaseInternalId . '_collection_' . $collectionInternalId);
+ } catch (\Exception $e) {
+ // Collection not found
+ if ($e->getMessage() !== 'Collection not found') {
+ throw $e;
+ }
+ }
+
+ // Compare with previous value
+ $diff = $value - $previousValue;
+
+ if ($diff === 0) {
+ break;
+ }
+
+ // Update Collection
+ $updateMetric($dbForProject, $diff, $key, $period, $time);
+
+ // Update Database
+ $databaseKey = str_replace(['{databaseInternalId}'], [$data[0]], METRIC_DATABASE_ID_STORAGE);
+ $updateMetric($dbForProject, $diff, $databaseKey, $period, $time);
+
+ // Update Project
+ $projectKey = METRIC_DATABASES_STORAGE;
+ $updateMetric($dbForProject, $diff, $projectKey, $period, $time);
+ break;
+ // Database Level
+ case METRIC_DATABASE_LEVEL_STORAGE:
+ Console::log('[' . DateTime::now() . '] Database Level Storage Calculation [' . $key . ']');
+ $databaseInternalId = $data[0];
+
+ $collections = [];
+ try {
+ $collections = $dbForProject->find('database_' . $databaseInternalId);
+ } catch (\Exception $e) {
+ // Database not found
+ if ($e->getMessage() !== 'Collection not found') {
+ throw $e;
+ }
+ }
+
+ foreach ($collections as $collection) {
+ try {
+ $value += $dbForProject->getSizeOfCollection('database_' . $databaseInternalId . '_collection_' . $collection->getInternalId());
+ } catch (\Exception $e) {
+ // Collection not found
+ if ($e->getMessage() !== 'Collection not found') {
+ throw $e;
+ }
+ }
+ }
+
+ $diff = $value - $previousValue;
+
+ if ($diff === 0) {
+ break;
+ }
+
+ // Update Database
+ $databaseKey = str_replace(['{databaseInternalId}'], [$data[0]], METRIC_DATABASE_ID_STORAGE);
+ $updateMetric($dbForProject, $diff, $databaseKey, $period, $time);
+
+ // Update Project
+ $projectKey = METRIC_DATABASES_STORAGE;
+ $updateMetric($dbForProject, $diff, $projectKey, $period, $time);
+ break;
+ // Project Level
+ case METRIC_PROJECT_LEVEL_STORAGE:
+ Console::log('[' . DateTime::now() . '] Project Level Storage Calculation [' . $key . ']');
+ // Get all project databases
+ $databases = $dbForProject->find('database');
+
+ // Recalculate all databases
+ foreach ($databases as $database) {
+ $collections = $dbForProject->find('database_' . $database->getInternalId());
+
+ foreach ($collections as $collection) {
+ try {
+ $value += $dbForProject->getSizeOfCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
+ } catch (\Exception $e) {
+ // Collection not found
+ if ($e->getMessage() !== 'Collection not found') {
+ throw $e;
+ }
+ }
+ }
+ }
+
+ $diff = $value - $previousValue;
+
+ // Update Project
+ $projectKey = METRIC_DATABASES_STORAGE;
+ $updateMetric($dbForProject, $diff, $projectKey, $period, $time);
+ break;
+ }
+ }
+
+ $end = microtime(true);
+
+ console::log('[' . DateTime::now() . '] DB Storage Calculation [' . $key . '] took ' . (($end - $start) * 1000) . ' milliseconds');
+ }
}
diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php
index 3074d59b7c..f7430ec70e 100644
--- a/src/Appwrite/Specification/Format/OpenAPI3.php
+++ b/src/Appwrite/Specification/Format/OpenAPI3.php
@@ -549,6 +549,7 @@ class OpenAPI3 extends Format
switch ($rule['type']) {
case 'string':
case 'datetime':
+ case 'payload':
$type = 'string';
break;
diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php
index 2eab7807b3..f2e324c71f 100644
--- a/src/Appwrite/Specification/Format/Swagger2.php
+++ b/src/Appwrite/Specification/Format/Swagger2.php
@@ -286,13 +286,26 @@ class Swagger2 extends Format
$validator = $validator->getValidator();
}
- $validatorClass = (!empty($validator)) ? \get_class($validator) : '';
- if ($validatorClass === 'Utopia\Validator\AnyOf') {
- $validator = $param['validator']->getValidators()[0];
- $validatorClass = \get_class($validator);
+ $class = !empty($validator)
+ ? \get_class($validator)
+ : '';
+
+ $base = !empty($class)
+ ? \get_parent_class($class)
+ : '';
+
+ switch ($base) {
+ case 'Appwrite\Utopia\Database\Validator\Queries\Base':
+ $class = $base;
+ break;
}
- switch ($validatorClass) {
+ if ($class === 'Utopia\Validator\AnyOf') {
+ $validator = $param['validator']->getValidators()[0];
+ $class = \get_class($validator);
+ }
+
+ switch ($class) {
case 'Utopia\Validator\Text':
case 'Utopia\Database\Validator\UID':
$node['type'] = $validator->getType();
@@ -348,29 +361,7 @@ class Swagger2 extends Format
$consumes = ['multipart/form-data'];
$node['type'] = 'payload';
break;
- case 'Appwrite\Utopia\Database\Validator\Queries\Attributes':
- case 'Appwrite\Utopia\Database\Validator\Queries\Buckets':
- case 'Appwrite\Utopia\Database\Validator\Queries\Collections':
- case 'Appwrite\Utopia\Database\Validator\Queries\Databases':
- case 'Appwrite\Utopia\Database\Validator\Queries\Deployments':
- case 'Appwrite\Utopia\Database\Validator\Queries\Executions':
- case 'Appwrite\Utopia\Database\Validator\Queries\Files':
- case 'Appwrite\Utopia\Database\Validator\Queries\Functions':
- case 'Appwrite\Utopia\Database\Validator\Queries\Identities':
- case 'Appwrite\Utopia\Database\Validator\Queries\Indexes':
- case 'Appwrite\Utopia\Database\Validator\Queries\Installations':
- case 'Appwrite\Utopia\Database\Validator\Queries\Memberships':
- case 'Appwrite\Utopia\Database\Validator\Queries\Messages':
- case 'Appwrite\Utopia\Database\Validator\Queries\Migrations':
- case 'Appwrite\Utopia\Database\Validator\Queries\Projects':
- case 'Appwrite\Utopia\Database\Validator\Queries\Providers':
- case 'Appwrite\Utopia\Database\Validator\Queries\Rules':
- case 'Appwrite\Utopia\Database\Validator\Queries\Subscribers':
- case 'Appwrite\Utopia\Database\Validator\Queries\Targets':
- case 'Appwrite\Utopia\Database\Validator\Queries\Teams':
- case 'Appwrite\Utopia\Database\Validator\Queries\Topics':
- case 'Appwrite\Utopia\Database\Validator\Queries\Users':
- case 'Appwrite\Utopia\Database\Validator\Queries\Variables':
+ case 'Appwrite\Utopia\Database\Validator\Queries\Base':
case 'Utopia\Database\Validator\Queries':
case 'Utopia\Database\Validator\Queries\Document':
case 'Utopia\Database\Validator\Queries\Documents':
@@ -585,6 +576,10 @@ class Swagger2 extends Format
$type = 'boolean';
break;
+ case 'payload':
+ $type = 'payload';
+ break;
+
default:
$type = 'object';
$rule['type'] = ($rule['type']) ?: 'none';
diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php
index a3555c08dd..af5d59ddfd 100644
--- a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php
+++ b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php
@@ -66,7 +66,7 @@ class Base extends Queries
new Limit(),
new Offset(),
new Cursor(),
- new Filter($attributes),
+ new Filter($attributes, APP_DATABASE_QUERY_MAX_VALUES),
new Order($attributes),
];
diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php
index 6b9e9e6d32..436a95534b 100644
--- a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php
+++ b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php
@@ -8,6 +8,7 @@ class Migrations extends Base
'status',
'stage',
'source',
+ 'destination',
'resources',
'statusCounters',
'resourceData',
diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php
index 3f0a196d5e..26c1baf188 100644
--- a/src/Appwrite/Utopia/Request.php
+++ b/src/Appwrite/Utopia/Request.php
@@ -122,7 +122,11 @@ class Request extends UtopiaRequest
*/
public function getHeaders(): array
{
- $headers = $this->generateHeaders();
+ try {
+ $headers = $this->generateHeaders();
+ } catch (\Throwable) {
+ $headers = [];
+ }
if (empty($this->swoole->cookie)) {
return $headers;
diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php
index a2c07d34b0..6cc2639f51 100644
--- a/src/Appwrite/Utopia/Response.php
+++ b/src/Appwrite/Utopia/Response.php
@@ -625,6 +625,11 @@ class Response extends SwooleResponse
}
}
+ if (!$data->isSet($key) && !$rule['required']) { // set output key null if data key is not set and required is false
+ $output[$key] = null;
+ continue;
+ }
+
if ($rule['array']) {
if (!is_array($data[$key])) {
throw new Exception($key . ' must be an array of type ' . $rule['type']);
diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php
index 8a0bb78cba..d14d1be0c1 100644
--- a/src/Appwrite/Utopia/Response/Model.php
+++ b/src/Appwrite/Utopia/Response/Model.php
@@ -14,6 +14,7 @@ abstract class Model
public const TYPE_DATETIME = 'datetime';
public const TYPE_DATETIME_EXAMPLE = '2020-10-15T06:38:00.000+00:00';
public const TYPE_RELATIONSHIP = 'relationship';
+ public const TYPE_PAYLOAD = 'payload';
/**
* @var bool
diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php
index 9f9ceca317..8c43f8d21c 100644
--- a/src/Appwrite/Utopia/Response/Model/Attribute.php
+++ b/src/Appwrite/Utopia/Response/Model/Attribute.php
@@ -47,7 +47,18 @@ class Attribute extends Model
'required' => false,
'example' => false,
])
- ;
+ ->addRule('$createdAt', [
+ 'type' => self::TYPE_DATETIME,
+ 'description' => 'Attribute creation date in ISO 8601 format.',
+ 'default' => '',
+ 'example' => self::TYPE_DATETIME_EXAMPLE,
+ ])
+ ->addRule('$updatedAt', [
+ 'type' => self::TYPE_DATETIME,
+ 'description' => 'Attribute update date in ISO 8601 format.',
+ 'default' => '',
+ 'example' => self::TYPE_DATETIME_EXAMPLE,
+ ]);
}
public array $conditions = [];
diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php
index 90fbdc9689..80b65af696 100644
--- a/src/Appwrite/Utopia/Response/Model/Execution.php
+++ b/src/Appwrite/Utopia/Response/Model/Execution.php
@@ -84,7 +84,6 @@ class Execution extends Model
'type' => self::TYPE_STRING,
'description' => 'HTTP response body. This will return empty unless execution is created as synchronous.',
'default' => '',
- 'example' => 'Developers are awesome.',
])
->addRule('responseHeaders', [
'type' => Response::MODEL_HEADERS,
diff --git a/src/Appwrite/Utopia/Response/Model/Index.php b/src/Appwrite/Utopia/Response/Model/Index.php
index 3d3d1a3b52..2d795ad439 100644
--- a/src/Appwrite/Utopia/Response/Model/Index.php
+++ b/src/Appwrite/Utopia/Response/Model/Index.php
@@ -49,13 +49,22 @@ class Index extends Model
'array' => true,
'required' => false,
])
- ;
+ ->addRule('$createdAt', [
+ 'type' => self::TYPE_DATETIME,
+ 'description' => 'Index creation date in ISO 8601 format.',
+ 'default' => '',
+ 'example' => self::TYPE_DATETIME_EXAMPLE,
+ ])
+ ->addRule('$updatedAt', [
+ 'type' => self::TYPE_DATETIME,
+ 'description' => 'Index update date in ISO 8601 format.',
+ 'default' => '',
+ 'example' => self::TYPE_DATETIME_EXAMPLE,
+ ]);
}
/**
* Get Name
- *
- * @return string
*/
public function getName(): string
{
@@ -64,8 +73,6 @@ class Index extends Model
/**
* Get Collection
- *
- * @return string
*/
public function getType(): string
{
diff --git a/src/Appwrite/Utopia/Response/Model/Migration.php b/src/Appwrite/Utopia/Response/Model/Migration.php
index 5a54eef3ad..f70dc37027 100644
--- a/src/Appwrite/Utopia/Response/Model/Migration.php
+++ b/src/Appwrite/Utopia/Response/Model/Migration.php
@@ -18,7 +18,7 @@ class Migration extends Model
])
->addRule('$createdAt', [
'type' => self::TYPE_DATETIME,
- 'description' => 'Variable creation date in ISO 8601 format.',
+ 'description' => 'Migration creation date in ISO 8601 format.',
'default' => '',
'example' => self::TYPE_DATETIME_EXAMPLE,
])
@@ -46,9 +46,15 @@ class Migration extends Model
'default' => '',
'example' => 'Appwrite',
])
+ ->addRule('destination', [
+ 'type' => self::TYPE_STRING,
+ 'description' => 'A string containing the type of destination of the migration.',
+ 'default' => 'Appwrite',
+ 'example' => 'Appwrite',
+ ])
->addRule('resources', [
'type' => self::TYPE_STRING,
- 'description' => 'Resources to migration.',
+ 'description' => 'Resources to migrate.',
'default' => [],
'example' => ['user'],
'array' => true
diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php
index 80214aaa73..e1d0105587 100644
--- a/src/Appwrite/Utopia/Response/Model/Project.php
+++ b/src/Appwrite/Utopia/Response/Model/Project.php
@@ -234,6 +234,18 @@ class Project extends Model
'default' => '',
'example' => 'tls',
])
+ ->addRule('pingCount', [
+ 'type' => self::TYPE_INTEGER,
+ 'description' => 'Number of times the ping was received for this project.',
+ 'default' => 0,
+ 'example' => 1,
+ ])
+ ->addRule('pingedAt', [
+ 'type' => self::TYPE_DATETIME,
+ 'description' => 'Last ping datetime in ISO 8601 format.',
+ 'default' => '',
+ 'example' => self::TYPE_DATETIME_EXAMPLE,
+ ])
;
$services = Config::getParam('services', []);
diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php
index d180b6c4c4..530749e006 100644
--- a/src/Appwrite/Utopia/Response/Model/Target.php
+++ b/src/Appwrite/Utopia/Response/Model/Target.php
@@ -32,7 +32,7 @@ class Target extends Model
'type' => self::TYPE_STRING,
'description' => 'Target Name.',
'default' => '',
- 'example' => 'Aegon apple token',
+ 'example' => 'Apple iPhone 12',
])
->addRule('userId', [
'type' => self::TYPE_STRING,
@@ -58,6 +58,12 @@ class Target extends Model
'description' => 'The target identifier.',
'default' => '',
'example' => 'token',
+ ])
+ ->addRule('expired', [
+ 'type' => self::TYPE_BOOLEAN,
+ 'description' => 'Is the target expired.',
+ 'default' => false,
+ 'example' => false,
]);
}
diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php
index d4733f2568..eb985baabb 100644
--- a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php
+++ b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php
@@ -28,6 +28,12 @@ class UsageDatabase extends Model
'default' => 0,
'example' => 0,
])
+ ->addRule('storageTotal', [
+ 'type' => self::TYPE_INTEGER,
+ 'description' => 'Total aggregated number of total storage used in bytes.',
+ 'default' => 0,
+ 'example' => 0,
+ ])
->addRule('collections', [
'type' => Response::MODEL_METRIC,
'description' => 'Aggregated number of collections per period.',
@@ -42,6 +48,13 @@ class UsageDatabase extends Model
'example' => [],
'array' => true
])
+ ->addRule('storage', [
+ 'type' => Response::MODEL_METRIC,
+ 'description' => 'Aggregated storage used in bytes per period.',
+ 'default' => [],
+ 'example' => [],
+ 'array' => true
+ ])
;
}
diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php
index f775f9489d..e0abba8ab8 100644
--- a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php
+++ b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php
@@ -34,6 +34,12 @@ class UsageDatabases extends Model
'default' => 0,
'example' => 0,
])
+ ->addRule('storageTotal', [
+ 'type' => self::TYPE_INTEGER,
+ 'description' => 'Total aggregated number of total databases storage in bytes.',
+ 'default' => 0,
+ 'example' => 0,
+ ])
->addRule('databases', [
'type' => Response::MODEL_METRIC,
'description' => 'Aggregated number of databases per period.',
@@ -55,6 +61,13 @@ class UsageDatabases extends Model
'example' => [],
'array' => true
])
+ ->addRule('storage', [
+ 'type' => Response::MODEL_METRIC,
+ 'description' => 'An array of the aggregated number of databases storage in bytes per period.',
+ 'default' => [],
+ 'example' => [],
+ 'array' => true
+ ])
;
}
diff --git a/src/Appwrite/Utopia/Response/Model/UsageProject.php b/src/Appwrite/Utopia/Response/Model/UsageProject.php
index 2703691238..17d9271f04 100644
--- a/src/Appwrite/Utopia/Response/Model/UsageProject.php
+++ b/src/Appwrite/Utopia/Response/Model/UsageProject.php
@@ -28,6 +28,12 @@ class UsageProject extends Model
'default' => 0,
'example' => 0,
])
+ ->addRule('databasesStorageTotal', [
+ 'type' => self::TYPE_INTEGER,
+ 'description' => 'Total aggregated sum of databases storage size (in bytes).',
+ 'default' => 0,
+ 'example' => 0,
+ ])
->addRule('usersTotal', [
'type' => self::TYPE_INTEGER,
'description' => 'Total aggregated number of users.',
@@ -118,6 +124,13 @@ class UsageProject extends Model
'example' => [],
'array' => true
])
+ ->addRule('databasesStorageBreakdown', [
+ 'type' => Response::MODEL_METRIC_BREAKDOWN,
+ 'description' => 'An array of the aggregated breakdown of storage usage by databases.',
+ 'default' => [],
+ 'example' => [],
+ 'array' => true
+ ])
->addRule('executionsMbSecondsBreakdown', [
'type' => Response::MODEL_METRIC_BREAKDOWN,
'description' => 'Aggregated breakdown in totals of execution mbSeconds by functions.',
diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php
index 0881966365..fe600cd0f8 100644
--- a/tests/e2e/General/HTTPTest.php
+++ b/tests/e2e/General/HTTPTest.php
@@ -133,7 +133,7 @@ class HTTPTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
// looks like recent change in the validator
- $this->assertTrue(empty($response['body']['schemaValidationMessages']));
+ $this->assertEmpty($response['body']['schemaValidationMessages'], 'Schema validation failed for ' . $file . ': ' . json_encode($response['body']['schemaValidationMessages'], JSON_PRETTY_PRINT));
}
}
diff --git a/tests/e2e/General/PingTest.php b/tests/e2e/General/PingTest.php
new file mode 100644
index 0000000000..e41bac6736
--- /dev/null
+++ b/tests/e2e/General/PingTest.php
@@ -0,0 +1,55 @@
+client->call(Client::METHOD_GET, '/ping', [
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]);
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals('Pong!', $response['body']);
+
+ // With user session
+ $response = $this->client->call(Client::METHOD_GET, '/ping', array_merge([
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals('Pong!', $response['body']);
+
+ // With API key
+ $response = $this->client->call(Client::METHOD_GET, '/ping', [
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey'],
+ ]);
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals('Pong!', $response['body']);
+
+ /**
+ * Test for FAILURE
+ */
+ // Fake project ID
+ $response = $this->client->call(Client::METHOD_GET, '/ping', \array_merge([
+ 'x-appwrite-project' => 'fake-project-id',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+ $this->assertNotContains('Pong!', $response['body']);
+ }
+}
diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php
index d3623acffc..c50a15fd3f 100644
--- a/tests/e2e/General/UsageTest.php
+++ b/tests/e2e/General/UsageTest.php
@@ -143,7 +143,7 @@ class UsageTest extends Scope
);
$this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals(20, count($response['body']));
+ $this->assertEquals(22, count($response['body']));
$this->validateDates($response['body']['network']);
$this->validateDates($response['body']['requests']);
$this->validateDates($response['body']['users']);
@@ -324,7 +324,7 @@ class UsageTest extends Scope
]
);
- $this->assertEquals(20, count($response['body']));
+ $this->assertEquals(22, count($response['body']));
$this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($response['body']['requests']);
@@ -545,7 +545,7 @@ class UsageTest extends Scope
]
);
- $this->assertEquals(20, count($response['body']));
+ $this->assertEquals(22, count($response['body']));
$this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals(1, count($response['body']['network']));
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
@@ -590,6 +590,260 @@ class UsageTest extends Scope
return $data;
}
+ public function testDatabaseStoragePrepare(): array
+ {
+ $response = $this->client->call(
+ Client::METHOD_POST,
+ '/databases',
+ array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id']
+ ], $this->getHeaders()),
+ [
+ 'databaseId' => 'unique()',
+ 'name' => 'dbStorageStats',
+ ]
+ );
+
+ $this->assertNotEmpty($response['body']['$id']);
+ $databaseId = $response['body']['$id'];
+
+ $response = $this->client->call(
+ Client::METHOD_POST,
+ '/databases/' . $databaseId . '/collections',
+ array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id']
+ ], $this->getHeaders()),
+ [
+ 'collectionId' => 'unique()',
+ 'name' => 'collectionStorageStats',
+ 'documentSecurity' => false,
+ 'permissions' => [
+ Permission::read(Role::any()),
+ Permission::create(Role::any()),
+ Permission::update(Role::any()),
+ Permission::delete(Role::any()),
+ ],
+ ]
+ );
+
+ $this->assertNotEmpty($response['body']['$id']);
+ $collectionId = $response['body']['$id'];
+
+ $response = $this->client->call(
+ Client::METHOD_POST,
+ '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string',
+ array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id']
+ ], $this->getHeaders()),
+ [
+ 'key' => 'data',
+ 'size' => 100000,
+ 'required' => true,
+ ]
+ );
+
+ return [
+ 'databaseId' => $databaseId,
+ 'collectionId' => $collectionId,
+ ];
+ }
+
+ // /** @depends testDatabaseStoragePrepare */
+ // #[Retry(count: 1)]
+ // public function testDatabaseStorageStatsCreateDocument(array $data): array
+ // {
+ // $databaseId = $data['databaseId'];
+ // $collectionId = $data['collectionId'];
+
+ // $originalProjectMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/project/usage',
+ // $this->getConsoleHeaders(),
+ // [
+ // 'period' => '1d',
+ // 'startDate' => self::getToday(),
+ // 'endDate' => self::getTomorrow(),
+ // ]
+ // );
+
+ // $this->assertEquals(200, $originalProjectMetrics['headers']['status-code']);
+ // $this->assertArrayHasKey('databasesStorageTotal', $originalProjectMetrics['body']);
+
+ // $originalProjectMetrics = $originalProjectMetrics['body'];
+
+ // $originalDatabaseMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/databases/' . $databaseId . '/usage?range=30d',
+ // $this->getConsoleHeaders()
+ // );
+
+ // $this->assertEquals(200, $originalDatabaseMetrics['headers']['status-code']);
+ // $this->assertArrayHasKey('storageTotal', $originalDatabaseMetrics['body']);
+ // $originalDatabaseMetrics = $originalDatabaseMetrics['body'];
+
+ // // Create documents
+ // for ($i = 0; $i < 100; $i++) {
+ // $response = $this->client->call(
+ // Client::METHOD_POST,
+ // '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents',
+ // array_merge([
+ // 'content-type' => 'application/json',
+ // 'x-appwrite-project' => $this->getProject()['$id']
+ // ], $this->getHeaders()),
+ // [
+ // 'documentId' => 'unique()',
+ // 'data' => ['data' => str_repeat('a', 10000)],
+ // ]
+ // );
+
+ // $this->assertEquals(201, $response['headers']['status-code']);
+ // }
+
+ // sleep(self::WAIT);
+
+ // for ($i = 0; $i < 3; $i++) {
+ // try {
+ // $newProjectMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/project/usage',
+ // $this->getConsoleHeaders(),
+ // [
+ // 'period' => '1d',
+ // 'startDate' => self::getToday(),
+ // 'endDate' => self::getTomorrow(),
+ // ]
+ // );
+
+ // $this->assertEquals(200, $newProjectMetrics['headers']['status-code']);
+ // $this->assertArrayHasKey('databasesStorageTotal', $newProjectMetrics['body']);
+ // $this->assertGreaterThan($originalProjectMetrics['databasesStorageTotal'], $newProjectMetrics['body']['databasesStorageTotal']);
+
+ // $newProjectMetrics = $newProjectMetrics['body'];
+
+ // $newDatabaseMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/databases/' . $databaseId . '/usage?range=30d',
+ // $this->getConsoleHeaders()
+ // );
+
+ // $this->assertEquals(200, $newDatabaseMetrics['headers']['status-code']);
+ // $this->assertArrayHasKey('storageTotal', $newDatabaseMetrics['body']);
+ // $this->assertGreaterThan($originalDatabaseMetrics['storageTotal'], $newDatabaseMetrics['body']['storageTotal']);
+
+ // $newDatabaseMetrics = $newDatabaseMetrics['body'];
+
+ // return [
+ // 'databaseId' => $databaseId,
+ // 'collectionId' => $collectionId,
+ // 'currentProjectMetrics' => $newProjectMetrics,
+ // 'currentDatabaseMetrics' => $newDatabaseMetrics,
+ // ];
+ // } catch (ExpectationFailedException $e) {
+ // if ($i === 2) {
+ // throw $e;
+ // }
+ // sleep(self::WAIT);
+ // continue;
+ // }
+ // }
+ // }
+
+ // /** @depends testDatabaseStorageStatsCreateDocument */
+ // #[Retry(count: 1)]
+ // public function testDatabaseStorageStatsDeleteDocument(array $data): array
+ // {
+ // $databaseId = $data['databaseId'];
+ // $collectionId = $data['collectionId'];
+ // $currentProjectMetrics = $data['currentProjectMetrics'];
+ // $currentDatabaseMetrics = $data['currentDatabaseMetrics'];
+
+ // $documents = $this->client->call(
+ // Client::METHOD_GET,
+ // '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents',
+ // array_merge([
+ // 'x-appwrite-project' => $this->getProject()['$id']
+ // ], $this->getHeaders()),
+ // [
+ // 'queries' => [
+ // Query::limit(50)->toString()
+ // ]
+ // ]
+ // );
+
+ // foreach ($documents['body']['documents'] as $document) {
+ // $response = $this->client->call(
+ // Client::METHOD_DELETE,
+ // '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document['$id'],
+ // array_merge([
+ // 'x-appwrite-project' => $this->getProject()['$id']
+ // ], $this->getHeaders())
+ // );
+
+ // $this->assertEquals(204, $response['headers']['status-code']);
+ // }
+
+ // sleep(self::WAIT);
+
+ // for ($i = 0; $i < 3; $i++) {
+ // try {
+ // $newProjectMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/project/usage',
+ // $this->getConsoleHeaders(),
+ // [
+ // 'period' => '1d',
+ // 'startDate' => self::getToday(),
+ // 'endDate' => self::getTomorrow(),
+ // ]
+ // );
+
+ // $this->assertEquals(200, $newProjectMetrics['headers']['status-code']);
+ // $this->assertArrayHasKey('databasesStorageTotal', $newProjectMetrics['body']);
+ // $this->assertLessThan($currentProjectMetrics['databasesStorageTotal'], $newProjectMetrics['body']['databasesStorageTotal']);
+
+ // $newProjectMetrics = $newProjectMetrics['body'];
+
+ // $newDatabaseMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/databases/' . $databaseId . '/usage?range=30d',
+ // $this->getConsoleHeaders()
+ // );
+
+ // $this->assertEquals(200, $newDatabaseMetrics['headers']['status-code']);
+ // $this->assertArrayHasKey('storageTotal', $newDatabaseMetrics['body']);
+ // $this->assertLessThan($currentDatabaseMetrics['storageTotal'], $newDatabaseMetrics['body']['storageTotal']);
+
+ // $newDatabaseMetrics = $newDatabaseMetrics['body'];
+
+ // return [
+ // 'databaseId' => $databaseId,
+ // 'collectionId' => $collectionId,
+ // 'currentProjectMetrics' => $newProjectMetrics,
+ // 'currentDatabaseMetrics' => $newDatabaseMetrics,
+ // ];
+ // } catch (ExpectationFailedException $e) {
+ // if ($i === 2) {
+ // throw $e;
+ // }
+ // sleep(self::WAIT);
+ // continue;
+ // }
+ // }
+
+ // $newProjectMetrics = $this->client->call(
+ // Client::METHOD_GET,
+ // '/project/usage',
+ // $this->getConsoleHeaders(),
+ // [
+ // 'period' => '1d',
+ // 'startDate' => self::getToday(),
+ // 'endDate' => self::getTomorrow(),
+ // ]
+ // );
+ // }
/** @depends testDatabaseStats */
public function testPrepareFunctionsStats(array $data): array
@@ -629,9 +883,6 @@ class UsageTest extends Scope
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz";
- $this->packageCode('php');
-
$response = $this->client->call(
Client::METHOD_POST,
'/functions/' . $functionId . '/deployments',
@@ -641,8 +892,8 @@ class UsageTest extends Scope
], $this->getHeaders()),
[
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
- 'activate' => true
+ 'code' => $this->packageFunction('php'),
+ 'activate' => true,
]
);
@@ -680,7 +931,7 @@ class UsageTest extends Scope
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[
- 'async' => false,
+ 'async' => 'false',
]
);
@@ -704,7 +955,7 @@ class UsageTest extends Scope
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[
- 'async' => false,
+ 'async' => 'false',
]
);
diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php
index 244f84b161..cca27cc3be 100644
--- a/tests/e2e/Services/Account/AccountCustomClientTest.php
+++ b/tests/e2e/Services/Account/AccountCustomClientTest.php
@@ -2695,4 +2695,45 @@ class AccountCustomClientTest extends Scope
return $data;
}
+
+ public function testCreatePushTarget(): void
+ {
+ $response = $this->client->call(Client::METHOD_POST, '/account/targets/push', \array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id']
+ ], $this->getHeaders()), [
+ 'targetId' => ID::unique(),
+ 'identifier' => 'test-identifier',
+ ]);
+
+ $this->assertEquals(201, $response['headers']['status-code']);
+ $this->assertNotEmpty($response['body']['$id']);
+ $this->assertEquals('test-identifier', $response['body']['identifier']);
+ }
+
+ public function testUpdatePushTarget(): void
+ {
+ $response = $this->client->call(Client::METHOD_POST, '/account/targets/push', \array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'targetId' => ID::unique(),
+ 'identifier' => 'test-identifier-2',
+ ]);
+
+ $this->assertEquals(201, $response['headers']['status-code']);
+ $this->assertNotEmpty($response['body']['$id']);
+ $this->assertEquals('test-identifier-2', $response['body']['identifier']);
+
+ $response = $this->client->call(Client::METHOD_PUT, '/account/targets/'. $response['body']['$id'] .'/push', \array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'identifier' => 'test-identifier-updated',
+ ]);
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals('test-identifier-updated', $response['body']['identifier']);
+ $this->assertEquals(false, $response['body']['expired']);
+ }
}
diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php
index 04f2dbd8c8..d079cb313c 100644
--- a/tests/e2e/Services/Databases/DatabasesBase.php
+++ b/tests/e2e/Services/Databases/DatabasesBase.php
@@ -1744,6 +1744,21 @@ trait DatabasesBase
$this->assertEquals(400, $documents['headers']['status-code']);
+ /**
+ * Test null value for cursor
+ */
+
+ $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'queries' => [
+ '{"method":"cursorAfter","values":[null]}',
+ ],
+ ]);
+
+ $this->assertEquals(400, $documents['headers']['status-code']);
+
return [];
}
@@ -2096,7 +2111,7 @@ trait DatabasesBase
*/
$conditions = [];
- for ($i = 0; $i < 101; $i++) {
+ for ($i = 0; $i < APP_DATABASE_QUERY_MAX_VALUES + 1; $i++) {
$conditions[] = $i;
}
@@ -2109,7 +2124,7 @@ trait DatabasesBase
],
]);
$this->assertEquals(400, $documents['headers']['status-code']);
- $this->assertEquals('Invalid query: Query on attribute has greater than 100 values: releaseYear', $documents['body']['message']);
+ $this->assertEquals('Invalid query: Query on attribute has greater than '.APP_DATABASE_QUERY_MAX_VALUES.' values: releaseYear', $documents['body']['message']);
$value = '';
diff --git a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php
index ca77cf2581..96bb0b5609 100644
--- a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php
+++ b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php
@@ -224,7 +224,7 @@ class DatabasesConsoleClientTest extends Scope
]);
$this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals(5, count($response['body']));
+ $this->assertEquals(7, count($response['body']));
$this->assertEquals('24h', $response['body']['range']);
$this->assertIsNumeric($response['body']['documentsTotal']);
$this->assertIsNumeric($response['body']['collectionsTotal']);
diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php
index 2d94b9f0e3..a1bb8f2b21 100644
--- a/tests/e2e/Services/Functions/FunctionsBase.php
+++ b/tests/e2e/Services/Functions/FunctionsBase.php
@@ -2,234 +2,207 @@
namespace Tests\E2E\Services\Functions;
+use Appwrite\Tests\Async;
+use CURLFile;
use Tests\E2E\Client;
use Utopia\CLI\Console;
trait FunctionsBase
{
+ use Async;
+
protected string $stdout = '';
protected string $stderr = '';
- protected function packageCode($folder)
+ protected function setupFunction(mixed $params): string
{
- Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
+ $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey'],
+ ]), $params);
+
+ $this->assertEquals($function['headers']['status-code'], 201, 'Setup function failed with status code: ' . $function['headers']['status-code'] . ' and response: ' . json_encode($function['body'], JSON_PRETTY_PRINT));
+
+ $functionId = $function['body']['$id'];
+
+ return $functionId;
}
- protected function awaitDeploymentIsBuilt($functionId, $deploymentId, $checkForSuccess = true): void
+ protected function setupDeployment(string $functionId, mixed $params): string
{
- while (true) {
- $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
+ 'content-type' => 'multipart/form-data',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey'],
+ ]), $params);
+ $this->assertEquals($deployment['headers']['status-code'], 202, 'Setup deployment failed with status code: ' . $deployment['headers']['status-code'] . ' and response: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
+ $deploymentId = $deployment['body']['$id'] ?? '';
+
+ $this->assertEventually(function () use ($functionId, $deploymentId) {
+ $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
- ]);
+ ]));
+ $this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
+ }, 50000, 500);
- if (
- $deployment['headers']['status-code'] >= 400
- || \in_array($deployment['body']['status'], ['ready', 'failed'])
- ) {
- break;
- }
-
- \sleep(1);
- }
-
- if ($checkForSuccess) {
- $this->assertEquals(200, $deployment['headers']['status-code']);
- $this->assertEquals('ready', $deployment['body']['status'], \json_encode($deployment['body']));
- }
+ return $deploymentId;
}
- // /**
- // * @depends testCreateTeam
- // */
- // public function testGetTeam($data):array
- // {
- // $id = $data['teamUid'] ?? '';
+ protected function cleanupFunction(string $functionId): void
+ {
+ $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey'],
+ ]));
- // /**
- // * Test for SUCCESS
- // */
- // $response = $this->client->call(Client::METHOD_GET, '/teams/'.$id, array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()));
+ $this->assertEquals($function['headers']['status-code'], 204);
+ }
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertNotEmpty($response['body']['$id']);
- // $this->assertEquals('Arsenal', $response['body']['name']);
- // $this->assertGreaterThan(-1, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertIsInt($response['body']['dateCreated']);
+ protected function createFunction(mixed $params): mixed
+ {
+ $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // /**
- // * Test for FAILURE
- // */
+ return $function;
+ }
- // return [];
- // }
+ protected function createVariable(string $functionId, mixed $params): mixed
+ {
+ $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // /**
- // * @depends testCreateTeam
- // */
- // public function testListTeams($data):array
- // {
- // /**
- // * Test for SUCCESS
- // */
- // $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()));
+ return $variable;
+ }
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertGreaterThan(0, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertCount(3, $response['body']['teams']);
+ protected function getFunction(string $functionId): mixed
+ {
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
- // $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'limit' => 2,
- // ]);
+ return $function;
+ }
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertGreaterThan(0, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertCount(2, $response['body']['teams']);
+ protected function getDeployment(string $functionId, string $deploymentId): mixed
+ {
+ $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
- // $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'offset' => 1,
- // ]);
+ return $deployment;
+ }
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertGreaterThan(0, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertCount(2, $response['body']['teams']);
+ protected function getExecution(string $functionId, $executionId): mixed
+ {
+ $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
- // $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'search' => 'Manchester',
- // ]);
+ return $execution;
+ }
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertGreaterThan(0, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertCount(1, $response['body']['teams']);
- // $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
+ protected function listFunctions(mixed $params = []): mixed
+ {
+ $functions = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'search' => 'United',
- // ]);
+ return $functions;
+ }
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertGreaterThan(0, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertCount(1, $response['body']['teams']);
- // $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
+ protected function listDeployments(string $functionId, $params = []): mixed
+ {
+ $deployments = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // /**
- // * Test for FAILURE
- // */
+ return $deployments;
+ }
- // return [];
- // }
+ protected function listExecutions(string $functionId, mixed $params = []): mixed
+ {
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // public function testUpdateTeam():array
- // {
- // /**
- // * Test for SUCCESS
- // */
- // $response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'name' => 'Demo'
- // ]);
+ return $executions;
+ }
- // $this->assertEquals(201, $response['headers']['status-code']);
- // $this->assertNotEmpty($response['body']['$id']);
- // $this->assertEquals('Demo', $response['body']['name']);
- // $this->assertGreaterThan(-1, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertIsInt($response['body']['dateCreated']);
+ protected function packageFunction(string $function): CURLFile
+ {
+ $folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
+ $tarPath = "$folderPath/code.tar.gz";
- // $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'name' => 'Demo New'
- // ]);
+ Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
- // $this->assertEquals(200, $response['headers']['status-code']);
- // $this->assertNotEmpty($response['body']['$id']);
- // $this->assertEquals('Demo New', $response['body']['name']);
- // $this->assertGreaterThan(-1, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertIsInt($response['body']['dateCreated']);
+ if (filesize($tarPath) > 1024 * 1024 * 5) {
+ throw new \Exception('Code package is too large. Use the chunked upload method instead.');
+ }
- // /**
- // * Test for FAILURE
- // */
- // $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // ]);
+ return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
+ }
- // $this->assertEquals(400, $response['headers']['status-code']);
+ protected function createDeployment(string $functionId, mixed $params = []): mixed
+ {
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
+ 'content-type' => 'multipart/form-data',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // return [];
- // }
+ return $deployment;
+ }
- // public function testDeleteTeam():array
- // {
- // /**
- // * Test for SUCCESS
- // */
- // $response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()), [
- // 'name' => 'Demo'
- // ]);
+ protected function getFunctionUsage(string $functionId, mixed $params): mixed
+ {
+ $usage = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // $teamUid = $response['body']['$id'];
+ return $usage;
+ }
- // $this->assertEquals(201, $response['headers']['status-code']);
- // $this->assertNotEmpty($response['body']['$id']);
- // $this->assertEquals('Demo', $response['body']['name']);
- // $this->assertGreaterThan(-1, $response['body']['total']);
- // $this->assertIsInt($response['body']['total']);
- // $this->assertIsInt($response['body']['dateCreated']);
+ protected function getTemplate(string $templateId)
+ {
+ $template = $this->client->call(Client::METHOD_GET, '/functions/templates/' . $templateId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
- // $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid, array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()));
+ return $template;
+ }
- // $this->assertEquals(204, $response['headers']['status-code']);
- // $this->assertEmpty($response['body']);
+ protected function createExecution(string $functionId, mixed $params = []): mixed
+ {
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), $params);
- // /**
- // * Test for FAILURE
- // */
- // $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([
- // 'content-type' => 'application/json',
- // 'x-appwrite-project' => $this->getProject()['$id'],
- // ], $this->getHeaders()));
+ return $execution;
+ }
- // $this->assertEquals(404, $response['headers']['status-code']);
+ protected function deleteFunction(string $functionId): mixed
+ {
+ $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
- // return [];
- // }
+ return $function;
+ }
}
diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php
index 8cb7f6f869..3a02cbcba2 100644
--- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php
+++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php
@@ -13,13 +13,11 @@ class FunctionsConsoleClientTest extends Scope
{
use ProjectCustom;
use SideConsole;
+ use FunctionsBase;
public function testCreateFunction(): array
{
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $function = $this->createFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::user($this->getUser()['$id'])->toString()],
@@ -35,10 +33,9 @@ class FunctionsConsoleClientTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $function['body']['$id'];
+
+ $function2 = $this->createFunction([
'functionId' => ID::unique(),
'name' => 'Test Failure',
'execute' => ['some-random-string'],
@@ -46,73 +43,59 @@ class FunctionsConsoleClientTest extends Scope
'entrypoint' => 'index.php',
]);
- $this->assertEquals(400, $response['headers']['status-code']);
+ $this->assertEquals(400, $function2['headers']['status-code']);
return [
- 'functionId' => $function['body']['$id']
+ 'functionId' => $functionId,
];
}
/**
* @depends testCreateFunction
*/
- public function testGetCollectionUsage(array $data)
+ public function testFunctionUsage(array $data)
{
- /**
- * Test for FAILURE
- */
-
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id']
- ], $this->getHeaders()), [
- 'range' => '232h'
- ]);
-
- $this->assertEquals(400, $response['headers']['status-code']);
-
- $response = $this->client->call(Client::METHOD_GET, '/functions/randomFunctionId/usage', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id']
- ], $this->getHeaders()), [
- 'range' => '24h'
- ]);
-
- $this->assertEquals(404, $response['headers']['status-code']);
-
/**
* Test for SUCCESS
*/
-
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id']
- ], $this->getHeaders()), [
+ $usage = $this->getFunctionUsage($data['functionId'], [
'range' => '24h'
]);
+ $this->assertEquals(200, $usage['headers']['status-code']);
+ $this->assertEquals(19, count($usage['body']));
+ $this->assertEquals('24h', $usage['body']['range']);
+ $this->assertIsNumeric($usage['body']['deploymentsTotal']);
+ $this->assertIsNumeric($usage['body']['deploymentsStorageTotal']);
+ $this->assertIsNumeric($usage['body']['buildsTotal']);
+ $this->assertIsNumeric($usage['body']['buildsStorageTotal']);
+ $this->assertIsNumeric($usage['body']['buildsTimeTotal']);
+ $this->assertIsNumeric($usage['body']['buildsMbSecondsTotal']);
+ $this->assertIsNumeric($usage['body']['executionsTotal']);
+ $this->assertIsNumeric($usage['body']['executionsTimeTotal']);
+ $this->assertIsNumeric($usage['body']['executionsMbSecondsTotal']);
+ $this->assertIsArray($usage['body']['deployments']);
+ $this->assertIsArray($usage['body']['deploymentsStorage']);
+ $this->assertIsArray($usage['body']['builds']);
+ $this->assertIsArray($usage['body']['buildsTime']);
+ $this->assertIsArray($usage['body']['buildsStorage']);
+ $this->assertIsArray($usage['body']['buildsTime']);
+ $this->assertIsArray($usage['body']['buildsMbSeconds']);
+ $this->assertIsArray($usage['body']['executions']);
+ $this->assertIsArray($usage['body']['executionsTime']);
+ $this->assertIsArray($usage['body']['executionsMbSeconds']);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals(19, count($response['body']));
- $this->assertEquals('24h', $response['body']['range']);
- $this->assertIsNumeric($response['body']['deploymentsTotal']);
- $this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
- $this->assertIsNumeric($response['body']['buildsTotal']);
- $this->assertIsNumeric($response['body']['buildsStorageTotal']);
- $this->assertIsNumeric($response['body']['buildsTimeTotal']);
- $this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
- $this->assertIsNumeric($response['body']['executionsTotal']);
- $this->assertIsNumeric($response['body']['executionsTimeTotal']);
- $this->assertIsNumeric($response['body']['executionsMbSecondsTotal']);
- $this->assertIsArray($response['body']['deployments']);
- $this->assertIsArray($response['body']['deploymentsStorage']);
- $this->assertIsArray($response['body']['builds']);
- $this->assertIsArray($response['body']['buildsTime']);
- $this->assertIsArray($response['body']['buildsStorage']);
- $this->assertIsArray($response['body']['buildsTime']);
- $this->assertIsArray($response['body']['buildsMbSeconds']);
- $this->assertIsArray($response['body']['executions']);
- $this->assertIsArray($response['body']['executionsTime']);
- $this->assertIsArray($response['body']['executionsMbSeconds']);
+ /**
+ * Test for FAILURE
+ */
+ $usage = $this->getFunctionUsage($data['functionId'], [
+ 'range' => '232h'
+ ]);
+ $this->assertEquals(400, $usage['headers']['status-code']);
+
+ $usage = $this->getFunctionUsage('randomFunctionId', [
+ 'range' => '24h'
+ ]);
+ $this->assertEquals(404, $usage['headers']['status-code']);
}
/**
@@ -123,31 +106,53 @@ class FunctionsConsoleClientTest extends Scope
/**
* Test for SUCCESS
*/
+ $variable = $this->createVariable(
+ $data['functionId'],
+ [
+ 'key' => 'APP_TEST',
+ 'value' => 'TESTINGVALUE'
+ ]
+ );
- $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => 'APP_TEST',
- 'value' => 'TESTINGVALUE'
- ]);
+ $this->assertEquals(201, $variable['headers']['status-code']);
- $this->assertEquals(201, $response['headers']['status-code']);
- $variableId = $response['body']['$id'];
+ $variableId = $variable['body']['$id'];
/**
* Test for FAILURE
*/
+ // Test for duplicate key
+ $variable = $this->createVariable(
+ $data['functionId'],
+ [
+ 'key' => 'APP_TEST',
+ 'value' => 'ANOTHERTESTINGVALUE'
+ ]
+ );
- $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => 'APP_TEST',
- 'value' => 'ANOTHER_TESTINGVALUE'
- ]);
+ $this->assertEquals(409, $variable['headers']['status-code']);
- $this->assertEquals(409, $response['headers']['status-code']);
+ // Test for invalid key
+ $variable = $this->createVariable(
+ $data['functionId'],
+ [
+ 'key' => str_repeat("A", 256),
+ 'value' => 'TESTINGVALUE'
+ ]
+ );
+
+ $this->assertEquals(400, $variable['headers']['status-code']);
+
+ // Test for invalid value
+ $variable = $this->createVariable(
+ $data['functionId'],
+ [
+ 'key' => 'LONGKEY',
+ 'value' => str_repeat("#", 8193),
+ ]
+ );
+
+ $this->assertEquals(400, $variable['headers']['status-code']);
return array_merge(
$data,
@@ -155,28 +160,6 @@ class FunctionsConsoleClientTest extends Scope
'variableId' => $variableId
]
);
-
- $longKey = str_repeat("A", 256);
- $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => $longKey,
- 'value' => 'TESTINGVALUE'
- ]);
-
- $this->assertEquals(400, $response['headers']['status-code']);
-
- $longValue = str_repeat("#", 8193);
- $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => 'LONGKEY',
- 'value' => $longValue
- ]);
-
- $this->assertEquals(400, $response['headers']['status-code']);
}
/**
diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
index 92b7c33034..914a255663 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
@@ -2,17 +2,12 @@
namespace Tests\E2E\Services\Functions;
-use Appwrite\Tests\Retry;
-use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideClient;
-use Utopia\Config\Config;
-use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Role;
-use Utopia\Database\Query;
class FunctionsCustomClientTest extends Scope
{
@@ -20,15 +15,12 @@ class FunctionsCustomClientTest extends Scope
use ProjectCustom;
use SideClient;
- public function testCreate(): array
+ public function testCreateFunction()
{
/**
- * Test for SUCCESS
+ * Test for FAILURE
*/
- $response1 = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $function = $this->createFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'events' => [
@@ -38,23 +30,15 @@ class FunctionsCustomClientTest extends Scope
'schedule' => '0 0 1 1 *',
'timeout' => 10,
]);
-
- $this->assertEquals(401, $response1['headers']['status-code']);
-
- return [];
+ $this->assertEquals(401, $function['headers']['status-code']);
}
- #[Retry(count: 2)]
- public function testCreateExecution(): array
+ public function testCreateExecution()
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::user($this->getUser()['$id'])->toString()],
@@ -64,291 +48,40 @@ class FunctionsCustomClientTest extends Scope
'users.*.create',
'users.*.delete',
],
- 'schedule' => '* * * * *', // execute every minute
'timeout' => 10,
]);
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- /** Create Variables */
- $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
- 'key' => 'funcKey1',
- 'value' => 'funcValue1',
- ]);
-
- $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
- 'key' => 'funcKey2',
- 'value' => 'funcValue2',
- ]);
-
- $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
- 'key' => 'funcKey3',
- 'value' => 'funcValue3',
- ]);
-
- $this->assertEquals(201, $variable['headers']['status-code']);
- $this->assertEquals(201, $variable2['headers']['status-code']);
- $this->assertEquals(201, $variable3['headers']['status-code']);
-
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/deployments', [
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
+ 'code' => $this->packageFunction('php'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
-
- $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(200, $function['headers']['status-code']);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', [
+ // Deny create async execution as guest
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], [
'async' => true,
]);
-
$this->assertEquals(401, $execution['headers']['status-code']);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Allow create async execution as user
+ $execution = $this->createExecution($functionId, [
'async' => true,
]);
-
$this->assertEquals(202, $execution['headers']['status-code']);
- // Wait for the first scheduled execution to be created
- sleep(90);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ]);
-
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertCount(2, $executions['body']['executions']);
- $this->assertIsArray($executions['body']['executions']);
- $this->assertEquals($executions['body']['executions'][1]['trigger'], 'schedule');
- $this->assertEquals($executions['body']['executions'][1]['status'], 'completed');
- $this->assertEquals($executions['body']['executions'][1]['responseStatusCode'], 200);
- $this->assertEquals($executions['body']['executions'][1]['responseBody'], '');
- $this->assertNotEmpty($executions['body']['executions'][1]['logs'], '');
- $this->assertNotEmpty($executions['body']['executions'][1]['errors'], '');
- $this->assertGreaterThan(0, $executions['body']['executions'][1]['duration']);
-
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $function['body']['$id'], [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
-
- return [];
+ $this->cleanupFunction($functionId);
}
- public function testCreateScheduledExecution(): void
- {
- /**
- * Test for SUCCESS
- */
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
- 'functionId' => ID::unique(),
- 'name' => 'Test',
- 'execute' => [Role::user($this->getUser()['$id'])->toString()],
- 'runtime' => 'php-8.0',
- 'entrypoint' => 'index.php',
- 'timeout' => 10,
- ]);
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/deployments', [
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
- 'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
- 'activate' => true
- ]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, true);
-
- // Schedule execution for the future
- \date_default_timezone_set('UTC');
- $futureTime = (new \DateTime())->add(new \DateInterval('PT2M'));
- $futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true,
- 'scheduledAt' => $futureTime->format(\DateTime::ATOM),
- 'path' => '/custom-path',
- 'method' => 'PATCH',
- 'body' => 'custom-body',
- 'headers' => [
- 'x-custom-header' => 'custom-value'
- ]
- ]);
-
- $this->assertEquals(202, $execution['headers']['status-code']);
- $this->assertEquals('scheduled', $execution['body']['status']);
- $this->assertEquals('PATCH', $execution['body']['requestMethod']);
- $this->assertEquals('/custom-path', $execution['body']['requestPath']);
- $this->assertCount(0, $execution['body']['requestHeaders']);
-
- $executionId = $execution['body']['$id'];
-
- $start = \microtime(true);
- while (true) {
- $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/executions/' . $executionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ]);
-
- if ($execution['body']['status'] === 'completed') {
- break;
- }
-
- $timeout = 60 + 60 + 15; // up to 1 minute round up, 1 minute schedule postpone, 15s cold start safety
- if (\microtime(true) - $start > $timeout) {
- $this->fail('Scheduled execution did not complete with status ' . $execution['body']['status'] . ': ' . \json_encode($execution));
- }
-
- usleep(500000); // 0.5 seconds
- }
-
- $this->assertEquals(200, $execution['headers']['status-code']);
- $this->assertEquals(200, $execution['body']['responseStatusCode']);
- $this->assertEquals('completed', $execution['body']['status']);
- $this->assertEquals('/custom-path', $execution['body']['requestPath']);
- $this->assertEquals('PATCH', $execution['body']['requestMethod']);
- $this->assertStringContainsString('body-is-custom-body', $execution['body']['logs']);
- $this->assertStringContainsString('custom-header-is-custom-value', $execution['body']['logs']);
- $this->assertStringContainsString('method-is-patch', $execution['body']['logs']);
- $this->assertStringContainsString('path-is-/custom-path', $execution['body']['logs']);
- $this->assertStringContainsString('user-is-' . $this->getUser()['$id'], $execution['body']['logs']);
- $this->assertStringContainsString('jwt-is-valid', $execution['body']['logs']);
- $this->assertGreaterThan(0, $execution['body']['duration']);
-
- /* Test for FAILURE */
-
- // Schedule synchronous execution
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => false,
- 'scheduledAt' => $futureTime->format(\DateTime::ATOM),
- ]);
-
- $this->assertEquals(400, $execution['headers']['status-code']);
-
- // Execution with seconds precision
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true,
- 'scheduledAt' => (new \DateTime("2100-12-08 16:12:02"))->format(\DateTime::ATOM)
- ]);
-
- $this->assertEquals(400, $execution['headers']['status-code']);
-
- // Execution with milliseconds precision
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true,
- 'scheduledAt' => (new \DateTime("2100-12-08 16:12:02.255"))->format(\DateTime::ATOM)
- ]);
-
- $this->assertEquals(400, $execution['headers']['status-code']);
-
- // Execution too soon
- $futureTime = (new \DateTime())->add(new \DateInterval('PT1M'));
- $futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true,
- 'scheduledAt' => $futureTime->format(\DateTime::ATOM),
- ]);
-
- $this->assertEquals(400, $execution['headers']['status-code']);
-
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $function['body']['$id'], [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
- }
public function testCreateCustomExecution(): array
{
/**
* Test for SUCCESS
*/
- $projectId = $this->getProject()['$id'];
- $apikey = $this->getProject()['apiKey'];
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::any()->toString()],
@@ -356,77 +89,16 @@ class FunctionsCustomClientTest extends Scope
'entrypoint' => 'index.php',
'timeout' => 10,
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- /** Create Variables */
- $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'key' => 'funcKey1',
- 'value' => 'funcValue1',
- ]);
-
- $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'key' => 'funcKey2',
- 'value' => 'funcValue2',
- ]);
-
- $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'key' => 'funcKey3',
- 'value' => 'funcValue3',
- ]);
-
- $this->assertEquals(201, $variable['headers']['status-code']);
- $this->assertEquals(201, $variable2['headers']['status-code']);
- $this->assertEquals(201, $variable3['headers']['status-code']);
-
- $folder = 'php-fn';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $deploymentId = $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
+ 'code' => $this->packageFunction('php-fn'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
-
- $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], []);
-
- $this->assertEquals(200, $function['headers']['status-code']);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'body' => 'foobar',
- 'async' => false
+ 'async' => 'false'
]);
-
$output = json_decode($execution['body']['responseBody'], true);
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals(200, $execution['body']['responseStatusCode']);
@@ -444,31 +116,20 @@ class FunctionsCustomClientTest extends Scope
$this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']);
$this->assertEquals($this->getUser()['$id'], $output['APPWRITE_FUNCTION_USER_ID']);
$this->assertNotEmpty($output['APPWRITE_FUNCTION_JWT']);
- $this->assertEquals($projectId, $output['APPWRITE_FUNCTION_PROJECT_ID']);
+ $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'body' => 'foobar',
'async' => true
]);
-
+ $executionId = $execution['body']['$id'];
$this->assertEquals(202, $execution['headers']['status-code']);
- $executionId = $execution['body']['$id'] ?? '';
-
- sleep(5);
-
- $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ]);
-
- $this->assertEmpty($execution['body']['responseBody']);
- $this->assertEquals(200, $execution['headers']['status-code']);
- $this->assertEquals(200, $execution['body']['responseStatusCode']);
+ $this->assertEventually(function () use ($functionId, $executionId) {
+ $execution = $this->getExecution($functionId, $executionId);
+ $this->assertEquals('completed', $execution['body']['status']);
+ $this->assertEquals(200, $execution['body']['responseStatusCode']);
+ }, 10000, 500);
return [
'functionId' => $functionId
@@ -480,14 +141,7 @@ class FunctionsCustomClientTest extends Scope
/**
* Test for SUCCESS
*/
- $projectId = $this->getProject()['$id'];
- $apikey = $this->getProject()['apiKey'];
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::any()->toString()],
@@ -500,56 +154,25 @@ class FunctionsCustomClientTest extends Scope
],
'timeout' => 10,
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $folder = 'php-fn';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
+ 'code' => $this->packageFunction('php-fn'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
-
- // Why do we have to do this?
- $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], []);
-
- $this->assertEquals(200, $function['headers']['status-code']);
-
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [
'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
+ 'x-appwrite-project' => $this->getProject()['$id'],
], [
'data' => 'foobar',
'async' => true,
]);
-
$this->assertEquals(202, $execution['headers']['status-code']);
}
- public function testCreateExecutionNoDeployment(): array
+ public function testCreateExecutionNoDeployment()
{
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [],
@@ -558,146 +181,18 @@ class FunctionsCustomClientTest extends Scope
'timeout' => 10,
]);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], [
- 'async' => true,
+ $execution = $this->createExecution($functionId, [
+ 'async' => true
]);
-
$this->assertEquals(404, $execution['headers']['status-code']);
-
- return [];
}
- /**
- * @depends testCreateCustomExecution
- */
- public function testListExecutions(array $data)
- {
- $functionId = $data['functionId'];
- $projectId = $this->getProject()['$id'];
- $apikey = $this->getProject()['apiKey'];
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- ], $this->getHeaders()), [
- 'data' => 'foobar'
- ]);
-
- $this->assertEquals(201, $execution['headers']['status-code']);
-
- $base = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ]);
-
- $this->assertEquals(200, $base['headers']['status-code']);
- $this->assertCount(3, $base['body']['executions']);
- $this->assertEquals('completed', $base['body']['executions'][0]['status']);
- $this->assertEquals('completed', $base['body']['executions'][1]['status']);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'queries' => [
- Query::limit(1)->toString(),
- ],
- ]);
-
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertCount(1, $executions['body']['executions']);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'queries' => [
- Query::offset(1)->toString(),
- ],
- ]);
-
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertCount(2, $executions['body']['executions']);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'queries' => [
- Query::equal('status', ['completed'])->toString(),
- ],
- ]);
-
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertCount(3, $executions['body']['executions']);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'queries' => [
- Query::equal('status', ['failed'])->toString(),
- ],
- ]);
-
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertCount(0, $executions['body']['executions']);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'queries' => [
- Query::cursorAfter(new Document(['$id' => $base['body']['executions'][0]['$id']]))->toString(),
- ],
- ]);
-
- $this->assertCount(2, $executions['body']['executions']);
- $this->assertEquals($base['body']['executions'][1]['$id'], $executions['body']['executions'][0]['$id']);
-
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'queries' => [
- Query::cursorBefore(new Document(['$id' => $base['body']['executions'][1]['$id']]))->toString(),
- ],
- ]);
-
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
- }
-
- public function testSynchronousExecution(): array
+ public function testSynchronousExecution()
{
/**
* Test for SUCCESS
*/
-
- $projectId = $this->getProject()['$id'];
- $apikey = $this->getProject()['apiKey'];
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::any()->toString()],
@@ -705,79 +200,16 @@ class FunctionsCustomClientTest extends Scope
'entrypoint' => 'index.php',
'timeout' => 10,
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- /** Create Variables */
- $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'key' => 'funcKey1',
- 'value' => 'funcValue1',
- ]);
-
- $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'key' => 'funcKey2',
- 'value' => 'funcValue2',
- ]);
-
- $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
- 'key' => 'funcKey3',
- 'value' => 'funcValue3',
- ]);
-
- $this->assertEquals(201, $variable['headers']['status-code']);
- $this->assertEquals(201, $variable2['headers']['status-code']);
- $this->assertEquals(201, $variable3['headers']['status-code']);
-
- $folder = 'php-fn';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $deploymentId = $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
+ 'code' => $this->packageFunction('php-fn'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
-
- $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ]);
-
- $this->assertEquals(200, $function['headers']['status-code']);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'body' => 'foobar',
- // Testing default value, should be 'async' => false
+ // Testing default value, should be 'async' => 'false'
]);
-
$output = json_decode($execution['body']['responseBody'], true);
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals('completed', $execution['body']['status']);
@@ -794,67 +226,29 @@ class FunctionsCustomClientTest extends Scope
$this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']);
$this->assertEquals($this->getUser()['$id'], $output['APPWRITE_FUNCTION_USER_ID']);
$this->assertNotEmpty($output['APPWRITE_FUNCTION_JWT']);
- $this->assertEquals($projectId, $output['APPWRITE_FUNCTION_PROJECT_ID']);
+ $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
// Client should never see logs and errors
$this->assertEmpty($execution['body']['logs']);
$this->assertEmpty($execution['body']['errors']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
-
- return [];
+ $this->cleanupFunction($functionId);
}
- public function testNonOverrideOfHeaders(): array
+ public function testNonOverrideOfHeaders()
{
- /**
- * Test for SUCCESS
- */
- $projectId = $this->getProject()['$id'];
- $apikey = $this->getProject()['apiKey'];
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::any()->toString()],
'runtime' => 'node-18.0',
'entrypoint' => 'index.js'
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $folder = 'node';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $projectId,
- 'x-appwrite-key' => $apikey,
- ], [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.js',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
+ 'code' => $this->packageFunction('node'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
-
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -871,16 +265,8 @@ class FunctionsCustomClientTest extends Scope
$this->assertNotEquals('OVERRIDDEN', $output['APPWRITE_FUNCTION_TRIGGER']);
$this->assertNotEquals('OVERRIDDEN', $output['APPWRITE_FUNCTION_USER_ID']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
- $this->assertEquals(204, $response['headers']['status-code']);
-
- return [];
+ $this->cleanupFunction($functionId);
}
public function testListTemplates()
@@ -888,7 +274,7 @@ class FunctionsCustomClientTest extends Scope
/**
* Test for SUCCESS
*/
- $expectedTemplates = array_slice(Config::getParam('function-templates', []), 0, 25);
+ // List all templates
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
'content-type' => 'application/json',
], $this->getHeaders()));
@@ -897,41 +283,35 @@ class FunctionsCustomClientTest extends Scope
$this->assertGreaterThan(0, $templates['body']['total']);
$this->assertIsArray($templates['body']['templates']);
- $this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
- $this->assertArrayHasKey('useCases', $templates['body']['templates'][0]);
- for ($i = 0; $i < 25; $i++) {
- $this->assertEquals($expectedTemplates[$i]['name'], $templates['body']['templates'][$i]['name']);
- $this->assertEquals($expectedTemplates[$i]['id'], $templates['body']['templates'][$i]['id']);
- $this->assertEquals($expectedTemplates[$i]['icon'], $templates['body']['templates'][$i]['icon']);
- $this->assertEquals($expectedTemplates[$i]['tagline'], $templates['body']['templates'][$i]['tagline']);
- $this->assertEquals($expectedTemplates[$i]['useCases'], $templates['body']['templates'][$i]['useCases']);
- $this->assertEquals($expectedTemplates[$i]['vcsProvider'], $templates['body']['templates'][$i]['vcsProvider']);
- $this->assertEquals($expectedTemplates[$i]['runtimes'], $templates['body']['templates'][$i]['runtimes']);
- $this->assertEquals($expectedTemplates[$i]['variables'], $templates['body']['templates'][$i]['variables']);
- if (array_key_exists('scopes', $expectedTemplates[$i])) {
- $this->assertEquals($expectedTemplates[$i]['scopes'], $templates['body']['templates'][$i]['scopes']);
- }
+ foreach ($templates['body']['templates'] as $template) {
+ $this->assertArrayHasKey('name', $template);
+ $this->assertArrayHasKey('id', $template);
+ $this->assertArrayHasKey('icon', $template);
+ $this->assertArrayHasKey('tagline', $template);
+ $this->assertArrayHasKey('useCases', $template);
+ $this->assertArrayHasKey('vcsProvider', $template);
+ $this->assertArrayHasKey('runtimes', $template);
+ $this->assertArrayHasKey('variables', $template);
}
- $templates_offset = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
+ // List templates with pagination
+ $templatesOffset = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
'content-type' => 'application/json',
], $this->getHeaders()), [
'limit' => 1,
'offset' => 2
]);
+ $this->assertEquals(200, $templatesOffset['headers']['status-code']);
+ $this->assertEquals(1, $templatesOffset['body']['total']);
+ $this->assertEquals($templates['body']['templates'][2]['id'], $templatesOffset['body']['templates'][0]['id']);
- $this->assertEquals(200, $templates_offset['headers']['status-code']);
- $this->assertEquals(1, $templates_offset['body']['total']);
- // assert that offset works as expected
- $this->assertEquals($templates['body']['templates'][2]['id'], $templates_offset['body']['templates'][0]['id']);
-
+ // List templates with filters
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
'content-type' => 'application/json',
], $this->getHeaders()), [
'useCases' => ['starter', 'ai'],
'runtimes' => ['bun-1.0', 'dart-2.16']
]);
-
$this->assertEquals(200, $templates['headers']['status-code']);
$this->assertGreaterThanOrEqual(3, $templates['body']['total']);
$this->assertIsArray($templates['body']['templates']);
@@ -941,6 +321,7 @@ class FunctionsCustomClientTest extends Scope
$this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
$this->assertContains('bun-1.0', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
+ // List templates with pagination and filters
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -955,24 +336,26 @@ class FunctionsCustomClientTest extends Scope
$this->assertEquals(5, $templates['body']['total']);
$this->assertIsArray($templates['body']['templates']);
$this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
+
foreach ($templates['body']['templates'] as $template) {
$this->assertContains($template['useCases'][0], ['databases']);
}
+
$this->assertContains('node-16.0', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
/**
* Test for FAILURE
*/
+ // List templates with invalid limit
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
'content-type' => 'application/json',
], $this->getHeaders()), [
'limit' => 5001,
'offset' => 10,
]);
-
$this->assertEquals(400, $templates['headers']['status-code']);
- $this->assertEquals('Invalid `limit` param: Value must be a valid range between 1 and 5,000', $templates['body']['message']);
+ // List templates with invalid offset
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -980,9 +363,7 @@ class FunctionsCustomClientTest extends Scope
'limit' => 5,
'offset' => 5001,
]);
-
$this->assertEquals(400, $templates['headers']['status-code']);
- $this->assertEquals('Invalid `offset` param: Value must be a valid range between 0 and 5,000', $templates['body']['message']);
}
public function testGetTemplate()
@@ -990,10 +371,7 @@ class FunctionsCustomClientTest extends Scope
/**
* Test for SUCCESS
*/
- $template = $this->client->call(Client::METHOD_GET, '/functions/templates/query-neo4j-auradb', array_merge([
- 'content-type' => 'application/json',
- ], $this->getHeaders()), []);
-
+ $template = $this->getTemplate('query-neo4j-auradb');
$this->assertEquals(200, $template['headers']['status-code']);
$this->assertIsArray($template['body']);
$this->assertEquals('query-neo4j-auradb', $template['body']['id']);
@@ -1002,15 +380,13 @@ class FunctionsCustomClientTest extends Scope
$this->assertEquals('Graph database with focus on relations between data.', $template['body']['tagline']);
$this->assertEquals(['databases'], $template['body']['useCases']);
$this->assertEquals('github', $template['body']['vcsProvider']);
+ $this->assertIsArray($template['body']['runtimes']);
+ $this->assertIsArray($template['body']['scopes']);
/**
* Test for FAILURE
*/
- $template = $this->client->call(Client::METHOD_GET, '/functions/templates/invalid-template-id', array_merge([
- 'content-type' => 'application/json',
- ], $this->getHeaders()), []);
-
+ $template = $this->getTemplate('invalid-template-id');
$this->assertEquals(404, $template['headers']['status-code']);
- $this->assertEquals('Function Template with the requested ID could not be found.', $template['body']['message']);
}
}
diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
index 2958e6cb5f..9b9f03a100 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
@@ -3,19 +3,17 @@
namespace Tests\E2E\Services\Functions;
use Appwrite\Functions\Specification;
-use Appwrite\Tests\Retry;
-use CURLFile;
-use PHPUnit\Framework\ExpectationFailedException;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideServer;
-use Utopia\App;
+use Utopia\CLI\Console;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
+use Utopia\System\System;
class FunctionsCustomServerTest extends Scope
{
@@ -23,15 +21,12 @@ class FunctionsCustomServerTest extends Scope
use ProjectCustom;
use SideServer;
- public function testCreate(): array
+ public function testCreateFunction(): array
{
/**
* Test for SUCCESS
*/
- $response1 = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $function = $this->createFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'runtime' => 'php-8.0',
@@ -40,48 +35,35 @@ class FunctionsCustomServerTest extends Scope
'buckets.*.create',
'buckets.*.delete',
],
- 'schedule' => '0 0 1 1 *',
'timeout' => 10,
]);
- $functionId = $response1['body']['$id'] ?? '';
+ $functionId = $functionId = $function['body']['$id'] ?? '';
- $this->assertEquals(201, $response1['headers']['status-code']);
- $this->assertNotEmpty($response1['body']['$id']);
- $this->assertEquals('Test', $response1['body']['name']);
- $this->assertEquals('php-8.0', $response1['body']['runtime']);
$dateValidator = new DatetimeValidator();
- $this->assertEquals(true, $dateValidator->isValid($response1['body']['$createdAt']));
- $this->assertEquals(true, $dateValidator->isValid($response1['body']['$updatedAt']));
- $this->assertEquals('', $response1['body']['deployment']);
+ $this->assertEquals(201, $function['headers']['status-code']);
+ $this->assertNotEmpty($function['body']['$id']);
+ $this->assertEquals('Test', $function['body']['name']);
+ $this->assertEquals('php-8.0', $function['body']['runtime']);
+ $this->assertEquals(true, $dateValidator->isValid($function['body']['$createdAt']));
+ $this->assertEquals(true, $dateValidator->isValid($function['body']['$updatedAt']));
+ $this->assertEquals('', $function['body']['deployment']);
$this->assertEquals([
'buckets.*.create',
'buckets.*.delete',
- ], $response1['body']['events']);
- $this->assertEquals('0 0 1 1 *', $response1['body']['schedule']);
- $this->assertEquals(10, $response1['body']['timeout']);
+ ], $function['body']['events']);
+ $this->assertEmpty($function['body']['schedule']);
+ $this->assertEquals(10, $function['body']['timeout']);
- /** Create Variables */
- $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $variable = $this->createVariable($functionId, [
'key' => 'funcKey1',
'value' => 'funcValue1',
]);
-
- $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $variable2 = $this->createVariable($functionId, [
'key' => 'funcKey2',
'value' => 'funcValue2',
]);
-
- $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $variable3 = $this->createVariable($functionId, [
'key' => 'funcKey3',
'value' => 'funcValue3',
]);
@@ -90,115 +72,90 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $variable2['headers']['status-code']);
$this->assertEquals(201, $variable3['headers']['status-code']);
- /**
- * Test for FAILURE
- */
-
return [
'functionId' => $functionId,
];
}
/**
- * @depends testCreate
+ * @depends testCreateFunction
*/
- public function testList(array $data): array
+ public function testListFunctions(array $data): array
{
/**
* Test for SUCCESS
*/
-
- /**
- * Test search queries
- */
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test search id
+ $functions = $this->listFunctions([
'search' => $data['functionId']
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
- $this->assertEquals($response['body']['functions'][0]['name'], 'Test');
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(1, $functions['body']['functions']);
+ $this->assertEquals($functions['body']['functions'][0]['name'], 'Test');
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test pagination limit
+ $functions = $this->listFunctions([
'queries' => [
Query::limit(1)->toString(),
],
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(1, $functions['body']['functions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test pagination offset
+ $functions = $this->listFunctions([
'queries' => [
Query::offset(1)->toString(),
],
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(0, $response['body']['functions']);
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(0, $functions['body']['functions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test filter enabled
+ $functions = $this->listFunctions([
'queries' => [
Query::equal('enabled', [true])->toString(),
],
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(1, $functions['body']['functions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test filter disabled
+ $functions = $this->listFunctions([
'queries' => [
Query::equal('enabled', [false])->toString(),
],
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(0, $response['body']['functions']);
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(0, $functions['body']['functions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test search name
+ $functions = $this->listFunctions([
'search' => 'Test'
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
- $this->assertEquals($response['body']['functions'][0]['$id'], $data['functionId']);
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(1, $functions['body']['functions']);
+ $this->assertEquals($functions['body']['functions'][0]['$id'], $data['functionId']);
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ // Test search runtime
+ $functions = $this->listFunctions([
'search' => 'php-8.0'
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
- $this->assertEquals($response['body']['functions'][0]['$id'], $data['functionId']);
+ $this->assertEquals($functions['headers']['status-code'], 200);
+ $this->assertCount(1, $functions['body']['functions']);
+ $this->assertEquals($functions['body']['functions'][0]['$id'], $data['functionId']);
/**
* Test pagination
*/
- $response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test 2',
'runtime' => 'php-8.0',
@@ -207,44 +164,10 @@ class FunctionsCustomServerTest extends Scope
'buckets.*.create',
'buckets.*.delete',
],
- 'schedule' => '0 0 1 1 *',
'timeout' => 10,
]);
- $this->assertNotEmpty($response['body']['$id']);
- /** Create Variables */
- $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $response['body']['$id'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => 'funcKey1',
- 'value' => 'funcValue1',
- ]);
-
- $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $response['body']['$id'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => 'funcKey2',
- 'value' => 'funcValue2',
- ]);
-
- $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $response['body']['$id'] . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'key' => 'funcKey3',
- 'value' => 'funcValue3',
- ]);
-
- $this->assertEquals(201, $variable['headers']['status-code']);
- $this->assertEquals(201, $variable2['headers']['status-code']);
- $this->assertEquals(201, $variable3['headers']['status-code']);
-
- $functions = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $functions = $this->listFunctions();
$this->assertEquals($functions['headers']['status-code'], 200);
$this->assertEquals($functions['body']['total'], 2);
@@ -253,61 +176,48 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($functions['body']['functions'][0]['name'], 'Test');
$this->assertEquals($functions['body']['functions'][1]['name'], 'Test 2');
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functions1 = $this->listFunctions([
'queries' => [
Query::cursorAfter(new Document(['$id' => $functions['body']['functions'][0]['$id']]))->toString(),
],
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
- $this->assertEquals($response['body']['functions'][0]['name'], 'Test 2');
+ $this->assertEquals($functions1['headers']['status-code'], 200);
+ $this->assertCount(1, $functions1['body']['functions']);
+ $this->assertEquals($functions1['body']['functions'][0]['name'], 'Test 2');
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functions2 = $this->listFunctions([
'queries' => [
Query::cursorBefore(new Document(['$id' => $functions['body']['functions'][1]['$id']]))->toString(),
],
]);
- $this->assertEquals($response['headers']['status-code'], 200);
- $this->assertCount(1, $response['body']['functions']);
- $this->assertEquals($response['body']['functions'][0]['name'], 'Test');
+ $this->assertEquals($functions2['headers']['status-code'], 200);
+ $this->assertCount(1, $functions2['body']['functions']);
+ $this->assertEquals($functions2['body']['functions'][0]['name'], 'Test');
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functions = $this->listFunctions([
'queries' => [
Query::cursorAfter(new Document(['$id' => 'unknown']))->toString(),
],
]);
-
- $this->assertEquals($response['headers']['status-code'], 400);
+ $this->assertEquals($functions['headers']['status-code'], 400);
return $data;
}
/**
- * @depends testList
+ * @depends testListFunctions
*/
- public function testGet(array $data): array
+ public function testGetFunction(array $data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $function = $this->getFunction($data['functionId']);
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['name'], 'Test');
@@ -315,10 +225,7 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for FAILURE
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/x', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $function = $this->getFunction('x');
$this->assertEquals($function['headers']['status-code'], 404);
@@ -326,14 +233,14 @@ class FunctionsCustomServerTest extends Scope
}
/**
- * @depends testGet
+ * @depends testGetFunction
*/
- public function testUpdate($data): array
+ public function testUpdateFunction($data): array
{
/**
* Test for SUCCESS
*/
- $response1 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
+ $function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -348,51 +255,35 @@ class FunctionsCustomServerTest extends Scope
'entrypoint' => 'index.php',
]);
- $this->assertEquals(200, $response1['headers']['status-code']);
- $this->assertNotEmpty($response1['body']['$id']);
- $this->assertEquals('Test1', $response1['body']['name']);
$dateValidator = new DatetimeValidator();
- $this->assertEquals(true, $dateValidator->isValid($response1['body']['$createdAt']));
- $this->assertEquals(true, $dateValidator->isValid($response1['body']['$updatedAt']));
- $this->assertEquals('', $response1['body']['deployment']);
+
+ $this->assertEquals(200, $function['headers']['status-code']);
+ $this->assertNotEmpty($function['body']['$id']);
+ $this->assertEquals('Test1', $function['body']['name']);
+ $this->assertEquals(true, $dateValidator->isValid($function['body']['$createdAt']));
+ $this->assertEquals(true, $dateValidator->isValid($function['body']['$updatedAt']));
+ $this->assertEquals('', $function['body']['deployment']);
$this->assertEquals([
'users.*.update.name',
'users.*.update.email',
- ], $response1['body']['events']);
- $this->assertEquals('0 0 1 1 *', $response1['body']['schedule']);
- $this->assertEquals(15, $response1['body']['timeout']);
+ ], $function['body']['events']);
+ $this->assertEquals('0 0 1 1 *', $function['body']['schedule']);
+ $this->assertEquals(15, $function['body']['timeout']);
- /**
- * Create global variable to test in execution later
- */
- $headers = [
- 'content-type' => 'application/json',
- 'origin' => 'http://localhost',
- 'cookie' => 'a_session_console=' . $this->getRoot()['session'],
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-mode' => 'admin',
- ];
-
- $variable = $this->client->call(Client::METHOD_POST, '/project/variables', $headers, [
+ // Create a variable for later tests
+ $variable = $this->createVariable($data['functionId'], [
'key' => 'GLOBAL_VARIABLE',
'value' => 'Global Variable Value',
]);
$this->assertEquals(201, $variable['headers']['status-code']);
- /**
- * Test for FAILURE
- */
-
return $data;
}
public function testCreateDeploymentFromCLI()
{
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::user($this->getUser()['$id'])->toString()],
@@ -402,150 +293,98 @@ class FunctionsCustomServerTest extends Scope
'users.*.create',
'users.*.delete',
],
- 'schedule' => '0 0 1 1 *',
+ 'schedule' => '0 0 1 1 *', // Once a year
'timeout' => 10,
]);
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $functionId = $function['body']['$id'];
-
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/deployments', [
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
'x-sdk-language' => 'cli',
], [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
+ 'code' => $this->packageFunction('php'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
$this->assertEquals(202, $deployment['headers']['status-code']);
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
+ $deploymentId = $deployment['body']['$id'] ?? '';
- $functionDetails = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
+ $this->assertEventually(function () use ($functionId, $deploymentId) {
+ $deployment = $this->getDeployment($functionId, $deploymentId);
- $this->assertEquals(200, $functionDetails['headers']['status-code']);
- $this->assertEquals('cli', $functionDetails['body']['type']);
+ $this->assertEquals(200, $deployment['headers']['status-code']);
+ $this->assertEquals('ready', $deployment['body']['status']);
+ $this->assertEquals('cli', $deployment['body']['type']);
+ }, 500000, 1000);
}
- public function testCreateDeploymentFromTemplate()
+ public function testCreateFunctionAndDeploymentFromTemplate()
{
- $runtimeName = 'php-8.0';
- // Fetch starter template (used to create function later)
- $template = $this->client->call(Client::METHOD_GET, '/functions/templates/starter', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $starterTemplate = $this->getTemplate('starter');
+ $this->assertEquals(200, $starterTemplate['headers']['status-code']);
- $this->assertEquals(200, $template['headers']['status-code']);
+ $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) {
+ return $runtime['name'] === 'php-8.0';
+ }))[0];
- $entrypoint = null;
- $rootDirectory = null;
- $commands = null;
- foreach ($template['body']['runtimes'] as $runtime) {
- if ($runtime["name"] !== $runtimeName) {
- continue;
- }
+ // If this fails, the template has variables, and this test needs to be updated
+ $this->assertEmpty($starterTemplate['body']['variables']);
- $entrypoint = $runtime["entrypoint"];
- $rootDirectory = $runtime["providerRootDirectory"];
- $commands = $runtime["commands"];
- break;
- }
-
- $this->assertNotNull($entrypoint);
-
- /**
- * If below test ever starts failing, it means temaplate used in
- * this test now has some variables. This test currently doesnt test variables.
- * Remove bellow assertion and update test to crete variable,
- * and ensure variable works as expected in execution.
- */
- $this->assertEmpty($template['body']['variables']);
-
- // Create function using settings from template.
- // Deployment is automatically created from template inside endpoint
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], $this->getHeaders()), [
- 'functionId' => ID::unique(),
- 'name' => $template['body']['name'],
- 'runtime' => $runtimeName,
- 'execute' => $template['body']['permissions'],
- 'entrypoint' => $entrypoint,
- 'events' => $template['body']['events'],
- 'schedule' => $template['body']['cron'],
- 'timeout' => $template['body']['timeout'],
- 'commands' => $commands,
- 'scopes' => $template['body']['scopes'],
- 'templateRepository' => $template['body']['providerRepositoryId'],
- 'templateOwner' => $template['body']['providerOwner'],
- 'templateRootDirectory' => $rootDirectory,
- 'templateVersion' => $template['body']['providerVersion'],
- ]);
+ $function = $this->createFunction(
+ [
+ 'functionId' => ID::unique(),
+ 'name' => $starterTemplate['body']['name'],
+ 'runtime' => 'php-8.0',
+ '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'],
+ 'templateRepository' => $starterTemplate['body']['providerRepositoryId'],
+ 'templateOwner' => $starterTemplate['body']['providerOwner'],
+ 'templateRootDirectory' => $phpRuntime['providerRootDirectory'],
+ 'templateVersion' => $starterTemplate['body']['providerVersion'],
+ ]
+ );
$this->assertEquals(201, $function['headers']['status-code']);
$this->assertNotEmpty($function['body']['$id']);
- $functionId = $function['body']['$id'];
+ $functionId = $functionId = $function['body']['$id'] ?? '';
- // List deployments so we can await deployment build
- $deployments = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments', [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
+ $deployments = $this->listDeployments($functionId);
$this->assertEquals(200, $deployments['headers']['status-code']);
$this->assertEquals(1, $deployments['body']['total']);
- $this->assertNotEmpty($deployments['body']['deployments'][0]['$id']);
- $this->assertEquals(0, $deployments['body']['deployments'][0]['size']);
- $deploymentId = $deployments['body']['deployments'][0]['$id'];
+ $lastDeployment = $deployments['body']['deployments'][0];
- // Wait for deployment build to finish
- // Deployment is automatically activated
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
+ $this->assertNotEmpty($lastDeployment['$id']);
+ $this->assertEquals(0, $lastDeployment['size']);
- $deployments = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
- $this->assertGreaterThan(0, $deployments['body']['size']);
+ $deploymentId = $lastDeployment['$id'];
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], $this->getHeaders()), []);
+ $this->assertEventually(function () use ($functionId, $deploymentId) {
+ $deployment = $this->getDeployment($functionId, $deploymentId);
+
+ $this->assertEquals(200, $deployment['headers']['status-code']);
+ $this->assertEquals('ready', $deployment['body']['status']);
+ }, 500000, 1000);
+
+ $function = $this->getFunction($functionId);
$this->assertEquals(200, $function['headers']['status-code']);
$this->assertEquals($deploymentId, $function['body']['deployment']);
- // Execute function to ensure starter code is used
- // Also tests if dynamic keys works as expected
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'path' => '/ping'
+ // Test starter code is used and that dynamic keys work
+ $execution = $this->createExecution($functionId, [
+ 'path' => '/ping',
]);
$this->assertEquals(201, $execution['headers']['status-code']);
@@ -554,7 +393,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals("Pong", $execution['body']['responseBody']);
$this->assertEmpty($execution['body']['errors']);
- // Get users to ensure execution logged correct total users
+ // Test execution logged correct total users
$users = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -564,15 +403,12 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $users['headers']['status-code']);
$this->assertIsInt($users['body']['total']);
- $totalusers = $users['body']['total'];
+ $totalUsers = $users['body']['total'];
- $this->assertStringContainsString("Total users: " . $totalusers, $execution['body']['logs']);
+ $this->assertStringContainsString("Total users: " . $totalUsers, $execution['body']['logs']);
// Execute function again but async
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'path' => '/ping',
'async' => true
]);
@@ -580,113 +416,93 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(202, $execution['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']);
$this->assertEquals('waiting', $execution['body']['status']);
- $executionId = $execution['body']['$id'];
- // Wait for async execuntion to finish
- sleep(5);
+ $executionId = $execution['body']['$id'] ?? '';
- // Ensure execution was successful
- $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
+ $this->assertEventually(function () use ($functionId, $executionId, $totalUsers) {
+ $execution = $this->getExecution($functionId, $executionId);
- $this->assertEquals(200, $execution['headers']['status-code']);
- $this->assertEquals("completed", $execution['body']['status']);
- $this->assertEquals(200, $execution['body']['responseStatusCode']);
- $this->assertEmpty($execution['body']['responseBody']);
- $this->assertEmpty($execution['body']['errors']);
- $this->assertStringContainsString("Total users: " . $totalusers, $execution['body']['logs']);
+ $this->assertEquals(200, $execution['headers']['status-code']);
+ $this->assertEquals(200, $execution['body']['responseStatusCode']);
+ $this->assertEquals('completed', $execution['body']['status']);
+ $this->assertEmpty($execution['body']['responseBody']);
+ $this->assertEmpty($execution['body']['errors']);
+ $this->assertStringContainsString("Total users: " . $totalUsers, $execution['body']['logs']);
+ }, 10000, 500);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $function = $this->deleteFunction($functionId);
}
/**
- * @depends testUpdate
+ * @depends testUpdateFunction
*/
public function testCreateDeployment($data): array
{
/**
* Test for SUCCESS
*/
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
+ $functionId = $data['functionId'];
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
+ $deployment = $this->createDeployment($functionId, [
+ 'code' => $this->packageFunction('php'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
$this->assertEquals(202, $deployment['headers']['status-code']);
$this->assertNotEmpty($deployment['body']['$id']);
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
- $this->awaitDeploymentIsBuilt($data['functionId'], $deploymentId);
+ $deploymentIdActive = $deployment['body']['$id'] ?? '';
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
+ $this->assertEventually(function () use ($functionId, $deploymentIdActive) {
+ $deployment = $this->getDeployment($functionId, $deploymentIdActive);
+
+ $this->assertEquals('ready', $deployment['body']['status']);
+ }, 50000, 500);
+
+ $deployment = $this->createDeployment($functionId, [
+ 'code' => $this->packageFunction('php'),
'activate' => 'false'
]);
$this->assertEquals(202, $deployment['headers']['status-code']);
$this->assertNotEmpty($deployment['body']['$id']);
- $deploymentIdInactive = $deployment['body']['$id'];
+ $deploymentIdInactive = $deployment['body']['$id'] ?? '';
- $this->awaitDeploymentIsBuilt($data['functionId'], $deploymentIdInactive);
+ $this->assertEventually(function () use ($functionId, $deploymentIdInactive) {
+ $deployment = $this->getDeployment($functionId, $deploymentIdInactive);
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $this->assertEquals('ready', $deployment['body']['status']);
+ }, 50000, 500);
+
+ $function = $this->getFunction($functionId);
$this->assertEquals(200, $function['headers']['status-code']);
- $this->assertEquals($deploymentId, $function['body']['deployment']);
+ $this->assertEquals($deploymentIdActive, $function['body']['deployment']);
$this->assertNotEquals($deploymentIdInactive, $function['body']['deployment']);
- $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentIdInactive, array_merge([
+ $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId . '/deployments/' . $deploymentIdInactive, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(204, $deployment['headers']['status-code']);
- return array_merge($data, ['deploymentId' => $deploymentId]);
+ return array_merge($data, ['deploymentId' => $deploymentIdActive]);
}
/**
- * @depends testUpdate
+ * @depends testUpdateFunction
*/
public function testCancelDeploymentBuild($data): void
{
- // Create a new deployment to cancel
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
+ $functionId = $data['functionId'];
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
- 'activate' => true
+ $deployment = $this->createDeployment($functionId, [
+ 'code' => $this->packageFunction('php'),
+ 'activate' => 'false'
]);
$deploymentId = $deployment['body']['$id'] ?? '';
@@ -696,33 +512,18 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
- // Poll until deployment is in progress
- while (true) {
- $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ]);
+ $this->assertEventually(function () use ($functionId, $deploymentId) {
+ $deployment = $this->getDeployment($functionId, $deploymentId);
- if (
- $deployment['headers']['status-code'] >= 400
- || $deployment['body']['status'] === 'building'
- ) {
- break;
- }
+ $this->assertEquals(200, $deployment['headers']['status-code']);
+ $this->assertEquals('building', $deployment['body']['status']);
+ }, 100000, 250);
- \sleep(1);
- }
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
- $this->assertEquals('building', $deployment['body']['status']);
-
- // Cancel the deployment build
- $cancel = $this->client->call(Client::METHOD_PATCH, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentId . '/build', [
+ // Cancel the deployment
+ $cancel = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId . '/build', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ]);
+ ], $this->getHeaders()));
$this->assertEquals(200, $cancel['headers']['status-code']);
$this->assertEquals('canceled', $cancel['body']['status']);
@@ -733,28 +534,26 @@ class FunctionsCustomServerTest extends Scope
* After build finished, it should still be canceled, not ready.
*/
\sleep(30);
- $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ]);
+
+ $deployment = $this->getDeployment($functionId, $deploymentId);
$this->assertEquals(200, $deployment['headers']['status-code']);
$this->assertEquals('canceled', $deployment['body']['status']);
}
/**
- * @depends testUpdate
+ * @depends testUpdateFunction
*/
public function testCreateDeploymentLarge($data): array
{
/**
* Test for Large Code File SUCCESS
*/
+ $functionId = $data['functionId'];
$folder = 'php-large';
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
+ Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
$chunkSize = 5 * 1024 * 1024;
$handle = @fopen($code, "rb");
@@ -772,7 +571,7 @@ class FunctionsCustomServerTest extends Scope
if (!empty($id)) {
$headers['x-appwrite-id'] = $id;
}
- $largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge($headers, $this->getHeaders()), [
+ $largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, $this->getHeaders()), [
'entrypoint' => 'index.php',
'code' => $curlFile,
'activate' => true,
@@ -791,19 +590,16 @@ class FunctionsCustomServerTest extends Scope
$this->assertLessThan(1024 * 1024 * 10, $largeTag['body']['size']); // ~7MB video file
$deploymentSize = $largeTag['body']['size'];
-
$deploymentId = $largeTag['body']['$id'];
- $this->awaitDeploymentIsBuilt($data['functionId'], $deploymentId, true);
+ $this->assertEventually(function () use ($functionId, $deploymentId, $deploymentSize) {
+ $deployment = $this->getDeployment($functionId, $deploymentId);
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals($deploymentSize, $response['body']['size']);
- $this->assertGreaterThan(1024 * 1024 * 10, $response['body']['buildSize']); // ~7MB video file + 10MB sample file
+ $this->assertEquals(200, $deployment['headers']['status-code']);
+ $this->assertEquals('ready', $deployment['body']['status']);
+ $this->assertEquals($deploymentSize, $deployment['body']['size']);
+ $this->assertGreaterThan(1024 * 1024 * 10, $deployment['body']['buildSize']); // ~7MB video file + 10MB sample file
+ }, 500000, 1000);
return $data;
}
@@ -816,6 +612,8 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
+ $dateValidator = new DatetimeValidator();
+
$response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -823,15 +621,10 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $dateValidator = new DatetimeValidator();
$this->assertEquals(true, $dateValidator->isValid($response['body']['$createdAt']));
$this->assertEquals(true, $dateValidator->isValid($response['body']['$updatedAt']));
$this->assertEquals($data['deploymentId'], $response['body']['deployment']);
- /**
- * Test for FAILURE
- */
-
return $data;
}
@@ -843,127 +636,64 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $functionId = $data['functionId'];
+ $deployments = $this->listDeployments($functionId);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals($function['body']['total'], 3);
- $this->assertIsArray($function['body']['deployments']);
- $this->assertCount(3, $function['body']['deployments']);
- $this->assertArrayHasKey('size', $function['body']['deployments'][0]);
- $this->assertArrayHasKey('buildSize', $function['body']['deployments'][0]);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals($deployments['body']['total'], 3);
+ $this->assertIsArray($deployments['body']['deployments']);
+ $this->assertCount(3, $deployments['body']['deployments']);
+ $this->assertArrayHasKey('size', $deployments['body']['deployments'][0]);
+ $this->assertArrayHasKey('buildSize', $deployments['body']['deployments'][0]);
- /**
- * Test search queries
- */
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders(), [
- 'search' => $data['functionId']
- ])
- );
-
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(3, $function['body']['total']);
- $this->assertIsArray($function['body']['deployments']);
- $this->assertCount(3, $function['body']['deployments']);
- $this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
-
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $deployments = $this->listDeployments($functionId, [
'queries' => [
Query::limit(1)->toString(),
],
]);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertCount(1, $function['body']['deployments']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertCount(1, $deployments['body']['deployments']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $deployments = $this->listDeployments($functionId, [
'queries' => [
Query::offset(1)->toString(),
],
]);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertCount(2, $function['body']['deployments']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertCount(2, $deployments['body']['deployments']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $deployments = $this->listDeployments($functionId, [
'queries' => [
Query::equal('entrypoint', ['index.php'])->toString(),
],
]);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertCount(3, $function['body']['deployments']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertCount(3, $deployments['body']['deployments']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $deployments = $this->listDeployments($functionId, [
'queries' => [
Query::equal('entrypoint', ['index.js'])->toString(),
],
]);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertCount(0, $function['body']['deployments']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertCount(0, $deployments['body']['deployments']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders(), [
- 'search' => 'Test'
- ])
- );
+ $deployments = $this->listDeployments($functionId, [
+ 'search' => 'php-8.0'
+ ]);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(3, $function['body']['total']);
- $this->assertIsArray($function['body']['deployments']);
- $this->assertCount(3, $function['body']['deployments']);
- $this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(3, $deployments['body']['total']);
+ $this->assertIsArray($deployments['body']['deployments']);
+ $this->assertCount(3, $deployments['body']['deployments']);
+ $this->assertEquals($deployments['body']['deployments'][0]['$id'], $data['deploymentId']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders(), [
- 'search' => 'php-8.0'
- ])
- );
-
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(3, $function['body']['total']);
- $this->assertIsArray($function['body']['deployments']);
- $this->assertCount(3, $function['body']['deployments']);
- $this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
-
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::equal('type', ['manual'])->toString(),
@@ -971,16 +701,11 @@ class FunctionsCustomServerTest extends Scope
]
);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(3, $function['body']['total']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(3, $deployments['body']['total']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::equal('type', ['vcs'])->toString(),
@@ -988,16 +713,11 @@ class FunctionsCustomServerTest extends Scope
]
);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(0, $function['body']['total']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(0, $deployments['body']['total']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::equal('type', ['invalid-string'])->toString(),
@@ -1005,16 +725,11 @@ class FunctionsCustomServerTest extends Scope
]
);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(0, $function['body']['total']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(0, $deployments['body']['total']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::greaterThan('size', 10000)->toString(),
@@ -1022,16 +737,11 @@ class FunctionsCustomServerTest extends Scope
]
);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(1, $function['body']['total']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(1, $deployments['body']['total']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::greaterThan('size', 0)->toString(),
@@ -1039,57 +749,41 @@ class FunctionsCustomServerTest extends Scope
]
);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(3, $function['body']['total']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(3, $deployments['body']['total']);
- $function = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::greaterThan('size', -100)->toString(),
],
]
);
-
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals(3, $function['body']['total']);
+ $this->assertEquals($deployments['headers']['status-code'], 200);
+ $this->assertEquals(3, $deployments['body']['total']);
/**
* Ensure size output and size filters work exactly.
* Prevents buildSize being counted towards deployemtn size
*/
- $response = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
Query::limit(1)->toString(),
]
);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertGreaterThanOrEqual(1, $response['body']['total']);
- $this->assertNotEmpty($response['body']['deployments'][0]['$id']);
- $this->assertNotEmpty($response['body']['deployments'][0]['size']);
+ $this->assertEquals(200, $deployments['headers']['status-code']);
+ $this->assertGreaterThanOrEqual(1, $deployments['body']['total']);
+ $this->assertNotEmpty($deployments['body']['deployments'][0]['$id']);
+ $this->assertNotEmpty($deployments['body']['deployments'][0]['size']);
- $deploymentId = $function['body']['deployments'][0]['$id'];
- $deploymentSize = $function['body']['deployments'][0]['size'];
+ $deploymentId = $deployments['body']['deployments'][0]['$id'];
+ $deploymentSize = $deployments['body']['deployments'][0]['size'];
- $response = $this->client->call(
- Client::METHOD_GET,
- '/functions/' . $data['functionId'] . '/deployments',
- array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),
+ $deployments = $this->listDeployments(
+ $functionId,
[
'queries' => [
Query::equal('size', [$deploymentSize])->toString(),
@@ -1097,20 +791,21 @@ class FunctionsCustomServerTest extends Scope
]
);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertGreaterThan(0, $response['body']['total']);
+ $this->assertEquals(200, $deployments['headers']['status-code']);
+ $this->assertGreaterThan(0, $deployments['body']['total']);
- $found = false;
- foreach ($response['body']['deployments'] as $deployment) {
- if ($deployment['$id'] === $deploymentId) {
- $found = true;
- $this->assertEquals($deploymentSize, $deployment['size']);
- break;
- }
+ $matchingDeployment = array_filter(
+ $deployments['body']['deployments'],
+ fn ($deployment) => $deployment['$id'] === $deploymentId
+ );
+
+ $this->assertNotEmpty($matchingDeployment, "Deployment with ID {$deploymentId} not found");
+
+ if (!empty($matchingDeployment)) {
+ $deployment = reset($matchingDeployment);
+ $this->assertEquals($deploymentSize, $deployment['size']);
}
- $this->assertTrue($found);
-
return $data;
}
@@ -1122,27 +817,21 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $deployment = $this->getDeployment($data['functionId'], $data['deploymentId']);
- $this->assertEquals(200, $function['headers']['status-code']);
- $this->assertGreaterThan(0, $function['body']['buildTime']);
- $this->assertNotEmpty($function['body']['status']);
- $this->assertNotEmpty($function['body']['buildLogs']);
- $this->assertArrayHasKey('size', $function['body']);
- $this->assertArrayHasKey('buildSize', $function['body']);
+ $this->assertEquals(200, $deployment['headers']['status-code']);
+ $this->assertGreaterThan(0, $deployment['body']['buildTime']);
+ $this->assertNotEmpty($deployment['body']['status']);
+ $this->assertNotEmpty($deployment['body']['buildLogs']);
+ $this->assertArrayHasKey('size', $deployment['body']);
+ $this->assertArrayHasKey('buildSize', $deployment['body']);
/**
* Test for FAILURE
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/x', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $deployment = $this->getDeployment($data['functionId'], 'x');
- $this->assertEquals($function['headers']['status-code'], 404);
+ $this->assertEquals($deployment['headers']['status-code'], 404);
return $data;
}
@@ -1155,15 +844,10 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => false,
+ $execution = $this->createExecution($data['functionId'], [
+ 'async' => 'false',
]);
- $executionId = $execution['body']['$id'] ?? '';
-
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']);
$this->assertNotEmpty($execution['body']['functionId']);
@@ -1183,13 +867,13 @@ class FunctionsCustomServerTest extends Scope
$this->assertNotEmpty($execution['body']['logs']);
$this->assertLessThan(10, $execution['body']['duration']);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => false,
+ $executionId = $execution['body']['$id'] ?? '';
+
+ $execution = $this->createExecution($data['functionId'], [
+ 'async' => 'false',
'path' => '/?code=400'
]);
+
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals('completed', $execution['body']['status']);
$this->assertEquals(400, $execution['body']['responseStatusCode']);
@@ -1198,6 +882,7 @@ class FunctionsCustomServerTest extends Scope
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
+
$this->assertEquals(204, $execution['headers']['status-code']);
return array_merge($data, ['executionId' => $executionId]);
@@ -1211,82 +896,62 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $executions = $this->listExecutions($data['functionId']);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals($function['body']['total'], 1);
- $this->assertIsArray($function['body']['executions']);
- $this->assertCount(1, $function['body']['executions']);
- $this->assertEquals($function['body']['executions'][0]['$id'], $data['executionId']);
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertEquals(1, $executions['body']['total']);
+ $this->assertIsArray($executions['body']['executions']);
+ $this->assertCount(1, $executions['body']['executions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $executions = $this->listExecutions($data['functionId'], [
'queries' => [
Query::limit(1)->toString(),
],
]);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertCount(1, $response['body']['executions']);
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertCount(1, $executions['body']['executions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $executions = $this->listExecutions($data['functionId'], [
'queries' => [
- Query::offset(1)->toString(),
+ Query::offset(0)->toString(),
],
]);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertCount(0, $response['body']['executions']);
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertCount(1, $executions['body']['executions']);
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $executions = $this->listExecutions($data['functionId'], [
'queries' => [
Query::equal('trigger', ['http'])->toString(),
],
]);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertCount(1, $response['body']['executions']);
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertCount(1, $executions['body']['executions']);
/**
* Test search queries
*/
-
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $executions = $this->listExecutions($data['functionId'], [
'search' => $data['executionId'],
]);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals(1, $response['body']['total']);
- $this->assertIsInt($response['body']['total']);
- $this->assertCount(1, $response['body']['executions']);
- $this->assertEquals($data['functionId'], $response['body']['executions'][0]['functionId']);
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertEquals(1, $executions['body']['total']);
+ $this->assertIsInt($executions['body']['total']);
+ $this->assertCount(1, $executions['body']['executions']);
+ $this->assertEquals($data['functionId'], $executions['body']['executions'][0]['functionId']);
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $executions = $this->listExecutions($data['functionId'], [
'search' => $data['functionId'],
]);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals(1, $response['body']['total']);
- $this->assertIsInt($response['body']['total']);
- $this->assertCount(1, $response['body']['executions']);
- $this->assertEquals($data['executionId'], $response['body']['executions'][0]['$id']);
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertEquals(1, $executions['body']['total']);
+ $this->assertIsInt($executions['body']['total']);
+ $this->assertCount(1, $executions['body']['executions']);
+ $this->assertEquals($data['executionId'], $executions['body']['executions'][0]['$id']);
return $data;
}
@@ -1294,17 +959,13 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testUpdateDeployment
*/
- #[Retry(count: 2)]
public function testSyncCreateExecution($data): array
{
/**
* Test for SUCCESS
*/
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- // Testing default value, should be 'async' => false
+ $execution = $this->createExecution($data['functionId'], [
+ // Testing default value, should be 'async' => 'false'
]);
$this->assertEquals(201, $execution['headers']['status-code']);
@@ -1328,21 +989,15 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $data['executionId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $execution = $this->getExecution($data['functionId'], $data['executionId']);
- $this->assertEquals($function['headers']['status-code'], 200);
- $this->assertEquals($function['body']['$id'], $data['executionId']);
+ $this->assertEquals($execution['headers']['status-code'], 200);
+ $this->assertEquals($execution['body']['$id'], $data['executionId']);
/**
* Test for FAILURE
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/x', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $function = $this->getExecution($data['functionId'], 'x');
$this->assertEquals($function['headers']['status-code'], 404);
@@ -1385,6 +1040,7 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
+
$this->assertEquals(202, $execution['headers']['status-code']);
$execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([
@@ -1399,46 +1055,18 @@ class FunctionsCustomServerTest extends Scope
return $data;
}
- /**
- * @depends testGetExecution
- */
- public function testDeleteScheduledExecution($data): array
- {
- $futureTime = (new \DateTime())->add(new \DateInterval('PT10H'));
- $futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true,
- 'scheduledAt' => $futureTime->format('Y-m-d H:i:s'),
- ]);
-
- $executionId = $execution['body']['$id'] ?? '';
- $this->assertEquals(202, $execution['headers']['status-code']);
- sleep(5);
- $execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
-
- $this->assertEquals(204, $execution['headers']['status-code']);
- $this->assertEmpty($execution['body']);
-
- return $data;
- }
/**
* @depends testGetExecution
*/
- #[Retry(count: 2)]
public function testUpdateSpecs($data): array
{
/**
* Test for SUCCESS
*/
- $response1 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
+ // Change the function specs
+ $function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1453,22 +1081,20 @@ class FunctionsCustomServerTest extends Scope
'specification' => Specification::S_1VCPU_1GB,
]);
- $this->assertEquals(200, $response1['headers']['status-code']);
- $this->assertNotEmpty($response1['body']['$id']);
- $this->assertEquals(Specification::S_1VCPU_1GB, $response1['body']['specification']);
+ $this->assertEquals(200, $function['headers']['status-code']);
+ $this->assertNotEmpty($function['body']['$id']);
+ $this->assertEquals(Specification::S_1VCPU_1GB, $function['body']['specification']);
- // Test Execution
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ // Verify the updated specs
+ $execution = $this->createExecution($data['functionId']);
$output = json_decode($execution['body']['responseBody'], true);
$this->assertEquals(1, $output['APPWRITE_FUNCTION_CPUS']);
$this->assertEquals(1024, $output['APPWRITE_FUNCTION_MEMORY']);
- $response2 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
+ // Change the specs to 1vcpu 512mb
+ $function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1483,15 +1109,12 @@ class FunctionsCustomServerTest extends Scope
'specification' => Specification::S_1VCPU_512MB,
]);
- $this->assertEquals(200, $response2['headers']['status-code']);
- $this->assertNotEmpty($response2['body']['$id']);
- $this->assertEquals(Specification::S_1VCPU_512MB, $response2['body']['specification']);
+ $this->assertEquals(200, $function['headers']['status-code']);
+ $this->assertNotEmpty($function['body']['$id']);
+ $this->assertEquals(Specification::S_1VCPU_512MB, $function['body']['specification']);
- // Test Execution
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ // Verify the updated specs
+ $execution = $this->createExecution($data['functionId']);
$output = json_decode($execution['body']['responseBody'], true);
@@ -1501,7 +1124,7 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for FAILURE
*/
- $response3 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
+ $function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1516,8 +1139,8 @@ class FunctionsCustomServerTest extends Scope
'specification' => 's-2vcpu-512mb', // Invalid specification
]);
- $this->assertEquals(400, $response3['headers']['status-code']);
- $this->assertStringStartsWith('Invalid `specification` param: Specification must be one of:', $response3['body']['message']);
+ $this->assertEquals(400, $function['headers']['status-code']);
+ $this->assertStringStartsWith('Invalid `specification` param: Specification must be one of:', $function['body']['message']);
return $data;
}
@@ -1530,24 +1153,17 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
+ $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
- $this->assertEquals(204, $function['headers']['status-code']);
- $this->assertEmpty($function['body']);
+ $this->assertEquals(204, $deployment['headers']['status-code']);
+ $this->assertEmpty($deployment['body']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $deployment = $this->getDeployment($data['functionId'], $data['deploymentId']);
- $this->assertEquals(404, $function['headers']['status-code']);
-
- /**
- * Test for FAILURE
- */
+ $this->assertEquals(404, $deployment['headers']['status-code']);
return $data;
}
@@ -1555,153 +1171,63 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testCreateDeployment
*/
- public function testDelete($data): array
+ public function testDeleteFunction($data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $function = $this->deleteFunction($data['functionId']);
$this->assertEquals(204, $function['headers']['status-code']);
$this->assertEmpty($function['body']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $function = $this->getFunction($data['functionId']);
$this->assertEquals(404, $function['headers']['status-code']);
- /**
- * Test for FAILURE
- */
-
return $data;
}
- public function testTimeout()
+ public function testExecutionTimeout()
{
- $name = 'php-8.0';
- $entrypoint = 'index.php';
- $timeout = 15;
- $folder = 'timeout';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
- 'name' => 'Test ' . $name,
- 'runtime' => $name,
- 'entrypoint' => $entrypoint,
+ 'name' => 'Test php-8.0',
+ 'runtime' => 'php-8.0',
+ 'entrypoint' => 'index.php',
'events' => [],
- 'schedule' => '* * * * *', // execute every minute
- 'timeout' => $timeout,
+ 'schedule' => '',
+ 'timeout' => 5, // Should timeout after 5 seconds
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
- $this->assertEquals('* * * * *', $function['body']['schedule']);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'entrypoint' => $entrypoint,
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ $this->setupDeployment($functionId, [
+ 'code' => $this->packageFunction('timeout'),
'activate' => true,
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($functionId, $deploymentId);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true,
+ $execution = $this->createExecution($functionId, [
+ 'async' => true
]);
- $executionId = $execution['body']['$id'] ?? '';
-
$this->assertEquals(202, $execution['headers']['status-code']);
- sleep(20);
+ $executionId = $execution['body']['$id'] ?? '';
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'queries' => [
- Query::equal('trigger', ['http'])->toString(),
- ],
- ]);
+ \sleep(5); // Wait for the function to timeout
- $this->assertEquals($executions['headers']['status-code'], 200);
- $this->assertEquals($executions['body']['total'], 1);
- $this->assertIsArray($executions['body']['executions']);
- $this->assertCount(1, $executions['body']['executions']);
- $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
- $this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
- $this->assertEquals($executions['body']['executions'][0]['status'], 'failed');
- $this->assertEquals($executions['body']['executions'][0]['responseStatusCode'], 500);
- $this->assertGreaterThan(2, $executions['body']['executions'][0]['duration']);
- $this->assertLessThan(20, $executions['body']['executions'][0]['duration']);
- $this->assertEquals($executions['body']['executions'][0]['responseBody'], '');
- $this->assertEquals($executions['body']['executions'][0]['logs'], '');
- $this->assertStringContainsString('timed out', $executions['body']['executions'][0]['errors']);
+ $this->assertEventually(function () use ($functionId, $executionId) {
+ $execution = $this->getExecution($functionId, $executionId);
- $start = \microtime(true);
- while (true) {
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'queries' => [
- Query::equal('trigger', ['schedule'])->toString(),
- ],
- ]);
+ $this->assertEquals(200, $execution['headers']['status-code']);
+ $this->assertEquals('failed', $execution['body']['status']);
+ $this->assertEquals(500, $execution['body']['responseStatusCode']);
+ $this->assertGreaterThan(2, $execution['body']['duration']);
+ $this->assertLessThan(20, $execution['body']['duration']);
+ $this->assertEquals('', $execution['body']['responseBody']);
+ $this->assertEquals('', $execution['body']['logs']);
+ $this->assertStringContainsString('timed out', $execution['body']['errors']);
+ }, 10000, 500);
- $this->assertEquals(200, $executions['headers']['status-code']);
-
- if (\count($executions['body']['executions']) > 0) {
- break;
- }
-
- // 0s would mean instant execution
- // +60 seconds, maximum possible waiting time before next minute
- // +10 seconds, maximum update interval time
- // +60 seconds, possible overlap between update and schedule tick
- // +10 seconds, maximum execution time including cold-start
- // Result: We allow maximum
- if (\microtime(true) - $start > 140) {
- $this->fail('Execution did not create within 140 seconds of schedule: ' . \json_encode($executions));
- }
-
- usleep(1000000); // 1 second
- }
-
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertGreaterThanOrEqual(1, \count($executions['body']['executions']));
- $this->assertEquals($executions['body']['executions'][0]['trigger'], 'schedule');
-
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
/**
@@ -1727,72 +1253,38 @@ class FunctionsCustomServerTest extends Scope
* @param string $entrypoint
*
* @dataProvider provideCustomExecutions
- * @depends testTimeout
+ * @depends testExecutionTimeout
*/
public function testCreateCustomExecution(string $folder, string $name, string $entrypoint, string $runtimeName, string $runtimeVersion)
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test ' . $name,
'runtime' => $name,
'entrypoint' => $entrypoint,
'events' => [],
- 'timeout' => $timeout,
+ 'timeout' => 15,
]);
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $variable = $this->createVariable($functionId, [
'key' => 'CUSTOM_VARIABLE',
- 'value' => 'variable',
+ 'value' => 'variable'
]);
$this->assertEquals(201, $variable['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $deploymentId = $this->setupDeployment($functionId, [
'entrypoint' => $entrypoint,
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction($folder),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'body' => 'foobar',
- 'async' => false
+ 'async' => 'false'
]);
- $executionId = $execution['body']['$id'] ?? '';
$output = json_decode($execution['body']['responseBody'], true);
-
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals('completed', $execution['body']['status']);
$this->assertEquals(200, $execution['body']['responseStatusCode']);
@@ -1811,10 +1303,9 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('Amazing Function Log', $execution['body']['logs']);
$this->assertEmpty($execution['body']['errors']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $executionId = $execution['body']['$id'] ?? '';
+
+ $executions = $this->listExecutions($functionId);
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['total'], 1);
@@ -1824,65 +1315,28 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
$this->assertStringContainsString('Amazing Function Log', $executions['body']['executions'][0]['logs']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testCreateCustomExecutionBinaryResponse()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-binary-response/code.tar.gz";
- $this->packageCode('php-binary-response');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Binary executions',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
- 'timeout' => $timeout,
+ 'timeout' => 15,
'execute' => ['any']
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-binary-response'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
- 'accept' => 'multipart/form-data',
+ 'accept' => 'multipart/form-data', // Accept binary response
], $this->getHeaders()), [
'body' => null,
]);
@@ -1902,7 +1356,7 @@ class FunctionsCustomServerTest extends Scope
*/
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
- 'accept' => 'application/json',
+ 'accept' => 'application/json', // Accept JSON response
], $this->getHeaders()), [
'body' => null,
]);
@@ -1910,66 +1364,29 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(400, $execution['headers']['status-code']);
$this->assertStringContainsString('Failed to parse response', $execution['body']['message']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testCreateCustomExecutionBinaryRequest()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-binary-request/code.tar.gz";
- $this->packageCode('php-binary-request');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Binary executions',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
- 'timeout' => $timeout,
+ 'timeout' => 15,
'execute' => ['any']
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-binary-request'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
$bytes = pack('C*', ...[0, 20, 255]);
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'multipart/form-data',
+ 'content-type' => 'multipart/form-data', // Send binary request
'x-appwrite-project' => $this->getProject()['$id'],
'accept' => 'application/json',
], $this->getHeaders()), [
@@ -1986,7 +1403,7 @@ class FunctionsCustomServerTest extends Scope
* Test for FAILURE
*/
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
+ 'content-type' => 'application/json', // Send JSON headers
'x-appwrite-project' => $this->getProject()['$id'],
'accept' => 'application/json',
], $this->getHeaders()), [
@@ -1994,98 +1411,53 @@ class FunctionsCustomServerTest extends Scope
], false);
$executionBody = json_decode($execution['body'], true);
+
$this->assertNotEquals(\md5($bytes), $executionBody['responseBody']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testv2Function()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-v2/code.tar.gz";
- $this->packageCode('php-v2');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP V2',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
'events' => [],
- 'timeout' => $timeout,
+ 'timeout' => 15,
]);
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $headers = [
+ $variable = $this->client->call(Client::METHOD_PATCH, '/mock/functions-v2', [
'content-type' => 'application/json',
'origin' => 'http://localhost',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-mode' => 'admin',
- ];
-
- $variable = $this->client->call(Client::METHOD_PATCH, '/mock/functions-v2', $headers, [
+ ], [
'functionId' => $functionId
]);
-
$this->assertEquals(204, $variable['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-v2'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'body' => 'foobar',
- 'async' => false
+ 'async' => 'false'
]);
- $output = json_decode($execution['body']['responseBody'], true);
-
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals('completed', $execution['body']['status']);
$this->assertEquals(200, $execution['body']['responseStatusCode']);
+
+ $output = json_decode($execution['body']['responseBody'], true);
$this->assertEquals(true, $output['v2Woks']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testGetRuntimes()
@@ -2113,14 +1485,7 @@ class FunctionsCustomServerTest extends Scope
public function testEventTrigger()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-event/code.tar.gz";
- $this->packageCode('php-event');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Event executions',
'runtime' => 'php-8.0',
@@ -2128,38 +1493,15 @@ class FunctionsCustomServerTest extends Scope
'events' => [
'users.*.create',
],
- 'timeout' => $timeout,
+ 'timeout' => 15,
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-event'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
- // Create user to trigger event
+ // Create user as an event trigger
$user = $this->client->call(Client::METHOD_POST, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -2168,108 +1510,59 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Event User'
]);
- $userId = $user['body']['$id'];
-
$this->assertEquals(201, $user['headers']['status-code']);
- // Wait for execution to occur
- sleep(15);
+ $userId = $user['body']['$id'] ?? '';
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $this->assertEventually(function () use ($functionId, $userId) {
+ $executions = $this->listExecutions($functionId);
- $execution = $executions['body']['executions'][0];
+ $lastExecution = $executions['body']['executions'][0];
- $this->assertEquals(200, $executions['headers']['status-code']);
- $this->assertEquals('completed', $execution['status']);
- $this->assertEquals(204, $execution['responseStatusCode']);
- $this->assertStringContainsString($userId, $execution['logs']);
- $this->assertStringContainsString('Event User', $execution['logs']);
+ $this->assertEquals('completed', $lastExecution['status']);
+ $this->assertEquals(204, $lastExecution['responseStatusCode']);
+ $this->assertStringContainsString($userId, $lastExecution['logs']);
+ $this->assertStringContainsString('Event User', $lastExecution['logs']);
+ }, 10000, 500);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
+ $this->cleanupFunction($functionId);
+
+ // Cleanup user
+ $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
-
- // Cleanup : Delete user
- $response = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->assertEquals(204, $user['headers']['status-code']);
}
public function testScopes()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-scopes/code.tar.gz";
- $this->packageCode('php-scopes');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Scopes executions',
- 'commands' => 'composer update --no-interaction --ignore-platform-reqs --optimize-autoloader --prefer-dist --no-dev',
+ 'commands' => 'sh setup.sh && composer install',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
'scopes' => ['users.read'],
- 'timeout' => $timeout,
+ 'timeout' => 15,
]);
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $deploymentId = $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'commands' => 'sh setup.sh && composer install',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
- 'activate' => true
+ 'code' => $this->packageFunction('php-scopes'),
+ 'activate' => true,
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
+ $deployment = $this->getDeployment($functionId, $deploymentId);
$this->assertEquals(200, $deployment['headers']['status-code']);
$this->assertStringContainsStringIgnoringCase("200 OK", $deployment['body']['buildLogs']);
$this->assertStringContainsStringIgnoringCase('"total":', $deployment['body']['buildLogs']);
$this->assertStringContainsStringIgnoringCase('"users":', $deployment['body']['buildLogs']);
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => false
+ $execution = $this->createExecution($functionId, [
+ 'async' => 'false',
]);
$this->assertEquals(201, $execution['headers']['status-code']);
@@ -2279,92 +1572,47 @@ class FunctionsCustomServerTest extends Scope
$this->assertNotEmpty($execution['body']['responseBody']);
$this->assertStringContainsString("total", $execution['body']['responseBody']);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => true
+ $execution = $this->createExecution($functionId, [
+ 'async' => true,
]);
$this->assertEquals(202, $execution['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']);
- \sleep(10);
+ $executionId = $execution['body']['$id'] ?? '';
- $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
+ $this->assertEventually(function () use ($functionId, $executionId) {
+ $execution = $this->getExecution($functionId, $executionId);
- $this->assertEquals(200, $execution['headers']['status-code']);
- $this->assertEquals('completed', $execution['body']['status']);
- $this->assertEquals(200, $execution['body']['responseStatusCode']);
- $this->assertGreaterThan(0, $execution['body']['duration']);
- $this->assertNotEmpty($execution['body']['logs']);
- $this->assertStringContainsString("total", $execution['body']['logs']);
+ $this->assertEquals(200, $execution['headers']['status-code']);
+ $this->assertEquals('completed', $execution['body']['status']);
+ $this->assertEquals(200, $execution['body']['responseStatusCode']);
+ $this->assertGreaterThan(0, $execution['body']['duration']);
+ $this->assertNotEmpty($execution['body']['logs']);
+ $this->assertStringContainsString("total", $execution['body']['logs']);
+ }, 10000, 500);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testCookieExecution()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-cookie/code.tar.gz";
- $this->packageCode('php-cookie');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Cookie executions',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
- 'timeout' => $timeout,
+ 'timeout' => 15,
]);
-
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-cookie'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
$cookie = 'cookieName=cookieValue; cookie2=value2; cookie3=value=3; cookie4=val:ue4; cookie5=value5';
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'async' => false,
+ $execution = $this->createExecution($functionId, [
+ 'async' => 'false',
'headers' => [
'cookie' => $cookie
]
@@ -2376,38 +1624,20 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($cookie, $execution['body']['responseBody']);
$this->assertGreaterThan(0, $execution['body']['duration']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testFunctionsDomain()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-cookie/code.tar.gz";
- $this->packageCode('php-cookie');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Cookie executions',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
- 'timeout' => $timeout,
+ 'timeout' => 15,
'execute' => ['any']
]);
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
$rules = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -2425,30 +1655,12 @@ class FunctionsCustomServerTest extends Scope
$domain = $rules['body']['rules'][0]['domain'];
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-cookie'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
$cookie = 'cookieName=cookieValue; cookie2=value2; cookie3=value=3; cookie4=val:ue4; cookie5=value5';
$proxyClient = new Client();
@@ -2463,67 +1675,45 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($cookie, $response['body']);
+ // Async execution document creation
+ $this->assertEventually(function () use ($functionId) {
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), []);
+
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertEquals(1, count($executions['body']['executions']));
+ });
+
// Await Aggregation
- sleep(App::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', 30));
+ sleep(System::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', 30));
- $tries = 0;
- while (true) {
- try {
- $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id']
- ], $this->getHeaders()), [
- 'range' => '24h'
- ]);
+ $this->assertEventually(function () use ($functionId) {
+ $response = $this->getFunctionUsage($functionId, [
+ 'range' => '24h'
+ ]);
- $this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals(19, count($response['body']));
- $this->assertEquals('24h', $response['body']['range']);
- $this->assertEquals(1, $response['body']['executionsTotal']);
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals(19, count($response['body']));
+ $this->assertEquals('24h', $response['body']['range']);
+ $this->assertEquals(1, $response['body']['executionsTotal']);
+ }, 25000, 1000);
- break;
- } catch (ExpectationFailedException $th) {
- if ($tries >= 5) {
- throw $th;
- } else {
- $tries++;
- sleep(5);
- }
- }
- }
-
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testFunctionsDomainBinaryResponse()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-binary-response/code.tar.gz";
- $this->packageCode('php-binary-response');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Binary executions',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
- 'timeout' => $timeout,
+ 'timeout' => 15,
'execute' => ['any']
]);
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
$rules = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -2541,30 +1731,12 @@ class FunctionsCustomServerTest extends Scope
$domain = $rules['body']['rules'][0]['domain'];
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-binary-response'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
@@ -2578,38 +1750,20 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(10, $bytes['byte2']);
$this->assertEquals(255, $bytes['byte3']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
public function testFunctionsDomainBinaryRequest()
{
- $timeout = 15;
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-binary-request/code.tar.gz";
- $this->packageCode('php-binary-request');
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test PHP Binary executions',
'runtime' => 'php-8.0',
'entrypoint' => 'index.php',
- 'timeout' => $timeout,
+ 'timeout' => 15,
'execute' => ['any']
]);
- $functionId = $function['body']['$id'] ?? '';
-
- $this->assertEquals(201, $function['headers']['status-code']);
-
$rules = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -2627,30 +1781,12 @@ class FunctionsCustomServerTest extends Scope
$domain = $rules['body']['rules'][0]['domain'];
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $this->setupDeployment($functionId, [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('php-binary-request'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
- $this->assertEquals(202, $deployment['headers']['status-code']);
-
- $this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
-
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
-
- $this->assertEquals(200, $deployment['headers']['status-code']);
-
- // Wait a little for activation to finish
- sleep(5);
-
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
@@ -2661,18 +1797,12 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(\md5($bytes), $response['body']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
- public function testCreateFunctionWithResponseFormatHeader()
+ public function testResponseFilters()
{
+ // create function with 1.5.0 response format
$response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -2686,28 +1816,75 @@ class FunctionsCustomServerTest extends Scope
]);
$this->assertEquals(201, $response['headers']['status-code']);
+ $this->assertArrayNotHasKey('scopes', $response['body']);
+ $this->assertArrayNotHasKey('specification', $response['body']);
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $response['body']['$id'], [
+ // get function with 1.5.0 response format header
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $response['body']['$id'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
+ 'x-appwrite-response-format' => '1.5.0', // add response format header
+ ], $this->getHeaders()));
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->assertEquals(200, $function['headers']['status-code']);
+ $this->assertArrayNotHasKey('scopes', $function['body']);
+ $this->assertArrayNotHasKey('specification', $function['body']);
+
+ $function = $this->getFunction($function['body']['$id']);
+
+ $this->assertEquals(200, $function['headers']['status-code']);
+ $this->assertArrayHasKey('scopes', $function['body']);
+ $this->assertArrayHasKey('specification', $function['body']);
+
+ $functionId = $function['body']['$id'] ?? '';
+ $this->cleanupFunction($functionId);
+ }
+
+ public function testRequestFilters()
+ {
+ $function1Id = $this->setupFunction([
+ 'functionId' => ID::unique(),
+ 'name' => 'Test',
+ 'runtime' => 'php-8.0',
+ 'entrypoint' => 'index.php',
+ 'timeout' => 15,
+ 'execute' => ['any']
+ ]);
+
+ $function2Id = $this->setupFunction([
+ 'functionId' => ID::unique(),
+ 'name' => 'Test2',
+ 'runtime' => 'php-8.0',
+ 'entrypoint' => 'index.php',
+ 'timeout' => 15,
+ 'execute' => ['any']
+ ]);
+
+ // list functions using request filters
+ $response = $this->client->call(
+ Client::METHOD_GET,
+ '/functions',
+ array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-response-format' => '1.4.0', // Set response format for 1.4 syntax
+ ], $this->getHeaders()),
+ [
+ 'queries' => [ 'equal("name", ["Test2"])' ]
+ ]
+ );
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertCount(1, $response['body']['functions']);
+ $this->assertEquals('Test2', $response['body']['functions'][0]['name']);
+
+ $this->cleanupFunction($function1Id);
+ $this->cleanupFunction($function2Id);
}
public function testFunctionLogging()
{
- // Preparations: Create Function
- $folder = 'node';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
- $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $function = $this->createFunction([
'functionId' => ID::unique(),
'runtime' => 'node-18.0',
'name' => 'Logging Test',
@@ -2720,38 +1897,22 @@ class FunctionsCustomServerTest extends Scope
$this->assertFalse($function['body']['logging']);
$this->assertNotEmpty($function['body']['$id']);
- $functionId = $function['body']['$id'];
+ $functionId = $functionId = $function['body']['$id'] ?? '';
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
- 'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ $this->setupDeployment($functionId, [
+ 'code' => $this->packageFunction('node'),
'activate' => true
]);
- $this->assertEquals(202, $deployment['headers']['status-code']);
- $this->assertNotEmpty($deployment['body']['$id']);
-
- $deploymentId = $deployment['body']['$id'] ?? '';
-
- $this->awaitDeploymentIsBuilt($functionId, $deploymentId, checkForSuccess: false);
-
// Sync Executions test
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), []);
+ $execution = $this->createExecution($functionId);
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEmpty($execution['body']['logs']);
$this->assertEmpty($execution['body']['errors']);
// Async Executions test
- $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $execution = $this->createExecution($functionId, [
'async' => true
]);
@@ -2760,19 +1921,16 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($execution['body']['errors']);
$this->assertNotEmpty($execution['body']['$id']);
- $executionId = $execution['body']['$id'];
+ $executionId = $execution['body']['$id'] ?? '';
- sleep(5);
+ $this->assertEventually(function () use ($functionId, $executionId) {
+ $execution = $this->getExecution($functionId, $executionId);
- $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
-
- $this->assertEquals(200, $execution['headers']['status-code']);
- $this->assertEquals('completed', $execution['body']['status']);
- $this->assertEmpty($execution['body']['logs']);
- $this->assertEmpty($execution['body']['errors']);
+ $this->assertEquals(200, $execution['headers']['status-code']);
+ $this->assertEquals('completed', $execution['body']['status']);
+ $this->assertEmpty($execution['body']['logs']);
+ $this->assertEmpty($execution['body']['errors']);
+ }, 10000, 500);
// Domain Executions test
$rules = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([
@@ -2800,10 +1958,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
+ $executions = $this->listExecutions($functionId, [
'queries' => [
Query::limit(1)->toString(),
Query::orderDesc('$id')->toString(),
@@ -2816,10 +1971,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($executions['body']['executions'][0]['errors']);
// Ensure executions count
- $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()));
+ $executions = $this->listExecutions($functionId);
$this->assertEquals(200, $executions['headers']['status-code']);
$this->assertCount(3, $executions['body']['executions']);
@@ -2830,13 +1982,6 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($execution['errors']);
}
- // Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- 'x-appwrite-key' => $this->getProject()['apiKey'],
- ], []);
-
- $this->assertEquals(204, $response['headers']['status-code']);
+ $this->cleanupFunction($functionId);
}
}
diff --git a/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php b/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php
new file mode 100644
index 0000000000..b1315103b1
--- /dev/null
+++ b/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php
@@ -0,0 +1,214 @@
+setupFunction([
+ 'functionId' => ID::unique(),
+ 'name' => 'Test',
+ 'execute' => [Role::user($this->getUser()['$id'])->toString()],
+ 'runtime' => 'php-8.0',
+ 'entrypoint' => 'index.php',
+ 'events' => [
+ 'users.*.create',
+ 'users.*.delete',
+ ],
+ 'schedule' => '* * * * *', // Execute every 60 seconds
+ 'timeout' => 10,
+ ]);
+
+ $this->setupDeployment($functionId, [
+ 'entrypoint' => 'index.php',
+ 'code' => $this->packageFunction('php'),
+ 'activate' => true
+ ]);
+
+ // Wait for scheduled execution
+ \sleep(60);
+
+ $this->assertEventually(function () use ($functionId) {
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey'],
+ ]);
+
+ $this->assertEquals(200, $executions['headers']['status-code']);
+ $this->assertCount(1, $executions['body']['executions']);
+
+ $asyncExecution = $executions['body']['executions'][0];
+
+ $this->assertEquals('schedule', $asyncExecution['trigger']);
+ $this->assertEquals('completed', $asyncExecution['status']);
+ $this->assertEquals(200, $asyncExecution['responseStatusCode']);
+ $this->assertEquals('', $asyncExecution['responseBody']);
+ $this->assertNotEmpty($asyncExecution['logs']);
+ $this->assertNotEmpty($asyncExecution['errors']);
+ $this->assertGreaterThan(0, $asyncExecution['duration']);
+ }, 60000, 500);
+
+ $this->cleanupFunction($functionId);
+ }
+
+ public function testCreateScheduledAtExecution(): void
+ {
+ /**
+ * Test for SUCCESS
+ */
+ $functionId = $this->setupFunction([
+ 'functionId' => ID::unique(),
+ 'name' => 'Test',
+ 'execute' => [Role::user($this->getUser()['$id'])->toString()],
+ 'runtime' => 'php-8.0',
+ 'entrypoint' => 'index.php',
+ 'timeout' => 10,
+ 'logging' => true,
+ ]);
+ $this->setupDeployment($functionId, [
+ 'entrypoint' => 'index.php',
+ 'code' => $this->packageFunction('php'),
+ 'activate' => true
+ ]);
+
+ // Schedule execution for the future
+ \date_default_timezone_set('UTC');
+ $futureTime = (new \DateTime())->add(new \DateInterval('PT2M')); // 2 minute in the future
+ $futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
+
+
+ $execution = $this->client->call(
+ Client::METHOD_POST,
+ '/functions/' . $functionId . '/executions',
+ [
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'origin' => 'http://localhost',
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $this->getUser()['session'],
+ ],
+ [
+ 'async' => true,
+ 'scheduledAt' => $futureTime->format(\DateTime::ATOM),
+ 'path' => '/custom-path',
+ 'method' => 'PATCH',
+ 'body' => 'custom-body',
+ 'headers' => [
+ 'x-custom-header' => 'custom-value'
+ ]
+ ]
+ );
+ $executionId = $execution['body']['$id'];
+
+ $this->assertEquals(202, $execution['headers']['status-code']);
+ $this->assertEquals('scheduled', $execution['body']['status']);
+ $this->assertEquals('PATCH', $execution['body']['requestMethod']);
+ $this->assertEquals('/custom-path', $execution['body']['requestPath']);
+ $this->assertCount(0, $execution['body']['requestHeaders']);
+
+ \sleep(120);
+
+ $this->assertEventually(function () use ($functionId, $executionId) {
+ $execution = $this->getExecution($functionId, $executionId);
+
+ $this->assertEquals(200, $execution['headers']['status-code']);
+ $this->assertEquals(200, $execution['body']['responseStatusCode']);
+ $this->assertEquals('completed', $execution['body']['status']);
+ $this->assertEquals('/custom-path', $execution['body']['requestPath']);
+ $this->assertEquals('PATCH', $execution['body']['requestMethod']);
+ $this->assertStringContainsString('body-is-custom-body', $execution['body']['logs']);
+ $this->assertStringContainsString('custom-header-is-custom-value', $execution['body']['logs']);
+ $this->assertStringContainsString('method-is-patch', $execution['body']['logs']);
+ $this->assertStringContainsString('path-is-/custom-path', $execution['body']['logs']);
+ $this->assertStringContainsString('user-is-' . $this->getUser()['$id'], $execution['body']['logs']);
+ $this->assertStringContainsString('jwt-is-valid', $execution['body']['logs']);
+ $this->assertGreaterThan(0, $execution['body']['duration']);
+ }, 10000, 500);
+
+ /* Test for FAILURE */
+ // Schedule synchronous execution
+ $execution = $this->createExecution($functionId, [
+ 'async' => 'false',
+ 'scheduledAt' => $futureTime->format(\DateTime::ATOM),
+ ]);
+ $this->assertEquals(400, $execution['headers']['status-code']);
+
+ // Execution with seconds precision
+ $execution = $this->createExecution($functionId, [
+ 'async' => true,
+ 'scheduledAt' => (new \DateTime("2100-12-08 16:12:02"))->format(\DateTime::ATOM)
+ ]);
+ $this->assertEquals(400, $execution['headers']['status-code']);
+
+ // Execution with milliseconds precision
+ $execution = $this->createExecution($functionId, [
+ 'async' => true,
+ 'scheduledAt' => (new \DateTime("2100-12-08 16:12:02.255"))->format(\DateTime::ATOM)
+ ]);
+ $this->assertEquals(400, $execution['headers']['status-code']);
+
+ // Execution too soon
+ $execution = $this->createExecution($functionId, [
+ 'async' => true,
+ 'scheduledAt' => (new \DateTime())->add(new \DateInterval('PT1S'))->format(\DateTime::ATOM)
+ ]);
+ $this->assertEquals(400, $execution['headers']['status-code']);
+
+ $this->cleanupFunction($functionId, $executionId);
+ }
+
+ public function testDeleteScheduledExecution()
+ {
+ $functionId = $this->setupFunction([
+ 'functionId' => ID::unique(),
+ 'name' => 'Test',
+ 'execute' => [Role::user($this->getUser()['$id'])->toString()],
+ 'runtime' => 'php-8.0',
+ 'entrypoint' => 'index.php',
+ 'timeout' => 10,
+ 'logging' => true,
+ ]);
+
+ $this->setupDeployment($functionId, [
+ 'entrypoint' => 'index.php',
+ 'code' => $this->packageFunction('php'),
+ 'activate' => true
+ ]);
+
+ $futureTime = (new \DateTime())->add(new \DateInterval('PT10H'));
+ $futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
+
+ $execution = $this->createExecution($functionId, [
+ 'async' => true,
+ 'scheduledAt' => $futureTime->format('Y-m-d H:i:s'),
+ ]);
+
+ $this->assertEquals(202, $execution['headers']['status-code']);
+
+ $executionId = $execution['body']['$id'] ?? '';
+
+ $execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
+
+ $this->assertEquals(204, $execution['headers']['status-code']);
+
+ $this->cleanupFunction($functionId);
+ }
+}
diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php
index 735e4eced5..0b3250cecf 100644
--- a/tests/e2e/Services/GraphQL/Base.php
+++ b/tests/e2e/Services/GraphQL/Base.php
@@ -2,6 +2,7 @@
namespace Tests\E2E\Services\GraphQL;
+use CURLFile;
use Utopia\CLI\Console;
trait Base
@@ -2496,8 +2497,17 @@ trait Base
protected string $stdout = '';
protected string $stderr = '';
- protected function packageCode($folder): void
+ protected function packageFunction(string $function): CURLFile
{
- Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
+ $folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
+ $tarPath = "$folderPath/code.tar.gz";
+
+ Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
+
+ if (filesize($tarPath) > 1024 * 1024 * 5) {
+ throw new \Exception('Code package is too large. Use the chunked upload method instead.');
+ }
+
+ return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
}
}
diff --git a/tests/e2e/Services/GraphQL/FunctionsClientTest.php b/tests/e2e/Services/GraphQL/FunctionsClientTest.php
index 3f0ee1966a..e7e8421254 100644
--- a/tests/e2e/Services/GraphQL/FunctionsClientTest.php
+++ b/tests/e2e/Services/GraphQL/FunctionsClientTest.php
@@ -2,7 +2,6 @@
namespace Tests\E2E\Services\GraphQL;
-use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
@@ -83,10 +82,6 @@ class FunctionsClientTest extends Scope
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$CREATE_DEPLOYMENT);
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
$gqlPayload = [
'operations' => \json_encode([
'query' => $query,
@@ -99,7 +94,7 @@ class FunctionsClientTest extends Scope
'map' => \json_encode([
'code' => ["variables.code"]
]),
- 'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'),
+ 'code' => $this->packageFunction('php')
];
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', [
diff --git a/tests/e2e/Services/GraphQL/FunctionsServerTest.php b/tests/e2e/Services/GraphQL/FunctionsServerTest.php
index 25a671fa1c..c3606244c4 100644
--- a/tests/e2e/Services/GraphQL/FunctionsServerTest.php
+++ b/tests/e2e/Services/GraphQL/FunctionsServerTest.php
@@ -2,7 +2,6 @@
namespace Tests\E2E\Services\GraphQL;
-use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
@@ -82,10 +81,6 @@ class FunctionsServerTest extends Scope
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$CREATE_DEPLOYMENT);
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
$gqlPayload = [
'operations' => \json_encode([
'query' => $query,
@@ -98,7 +93,7 @@ class FunctionsServerTest extends Scope
'map' => \json_encode([
'code' => ["variables.code"]
]),
- 'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'),
+ 'code' => $this->packageFunction('php'),
];
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php
index 8360af542e..9d6a04abe6 100644
--- a/tests/e2e/Services/Health/HealthCustomServerTest.php
+++ b/tests/e2e/Services/Health/HealthCustomServerTest.php
@@ -455,7 +455,7 @@ class HealthCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('/CN=www.google.com', $response['body']['name']);
$this->assertEquals('www.google.com', $response['body']['subjectSN']);
- $this->assertStringContainsString('Google Trust Services', $response['body']['issuerOrganisation']);
+ $this->assertContains($response['body']['issuerOrganisation'], ['Let\'s Encrypt', 'Google Trust Services']);
$this->assertIsInt($response['body']['validFrom']);
$this->assertIsInt($response['body']['validTo']);
@@ -467,7 +467,7 @@ class HealthCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('/CN=appwrite.io', $response['body']['name']);
$this->assertEquals('appwrite.io', $response['body']['subjectSN']);
- $this->assertEquals("Let's Encrypt", $response['body']['issuerOrganisation']);
+ $this->assertContains($response['body']['issuerOrganisation'], ['Let\'s Encrypt', 'Google Trust Services']);
$this->assertIsInt($response['body']['validFrom']);
$this->assertIsInt($response['body']['validTo']);
diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php
index c41d861f1d..7b0847126c 100644
--- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php
+++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php
@@ -101,7 +101,7 @@ class ProjectsConsoleClientTest extends Scope
'region' => 'default'
]);
- $this->assertEquals(400, $response['headers']['status-code']);
+ $this->assertEquals(401, $response['headers']['status-code']);
return [
'projectId' => $projectId,
@@ -546,7 +546,7 @@ class ProjectsConsoleClientTest extends Scope
'name' => '',
]);
- $this->assertEquals(400, $response['headers']['status-code']);
+ $this->assertEquals(401, $response['headers']['status-code']);
return ['projectId' => $projectId];
}
@@ -3793,4 +3793,272 @@ class ProjectsConsoleClientTest extends Scope
return $data;
}
+
+ /**
+ * @depends testCreateProject
+ */
+ public function testCreateProjectVariable(array $data)
+ {
+ /**
+ * Test for SUCCESS
+ */
+ $variable = $this->client->call(Client::METHOD_POST, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => 'APP_TEST',
+ 'value' => 'TESTINGVALUE'
+ ]);
+
+ $this->assertEquals(201, $variable['headers']['status-code']);
+ $variableId = $variable['body']['$id'];
+
+ /**
+ * Test for FAILURE
+ */
+ // Test for duplicate key
+ $variable = $this->client->call(Client::METHOD_POST, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => 'APP_TEST',
+ 'value' => 'ANOTHERTESTINGVALUE'
+ ]);
+
+ $this->assertEquals(409, $variable['headers']['status-code']);
+
+ // Test for invalid key
+ $variable = $this->client->call(Client::METHOD_POST, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => str_repeat("A", 256),
+ 'value' => 'TESTINGVALUE'
+ ]);
+
+ $this->assertEquals(400, $variable['headers']['status-code']);
+
+ // Test for invalid value
+ $variable = $this->client->call(Client::METHOD_POST, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => 'LONGKEY',
+ 'value' => str_repeat("#", 8193),
+ ]);
+
+ $this->assertEquals(400, $variable['headers']['status-code']);
+
+ return array_merge(
+ $data,
+ [
+ 'variableId' => $variableId,
+ ]
+ );
+ }
+
+ /**
+ * @depends testCreateProjectVariable
+ */
+ public function testListVariables(array $data)
+ {
+ /**
+ * Test for SUCCESS
+ */
+
+ $response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertCount(1, $response['body']['variables']);
+ $this->assertEquals(1, $response['body']['total']);
+ $this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']);
+ $this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']);
+
+ return $data;
+ }
+
+ /**
+ * @depends testListVariables
+ */
+ public function testGetVariable(array $data)
+ {
+ /**
+ * Test for SUCCESS
+ */
+ $response = $this->client->call(Client::METHOD_GET, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals("APP_TEST", $response['body']['key']);
+ $this->assertEquals("TESTINGVALUE", $response['body']['value']);
+
+ /**
+ * Test for FAILURE
+ */
+
+ $response = $this->client->call(Client::METHOD_GET, '/project/variables/NON_EXISTING_VARIABLE', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+ return $data;
+ }
+
+ /**
+ * @depends testGetVariable
+ */
+ public function testUpdateVariable(array $data)
+ {
+ /**
+ * Test for SUCCESS
+ */
+
+ $response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => 'APP_TEST_UPDATE',
+ 'value' => 'TESTINGVALUEUPDATED'
+ ]);
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals("APP_TEST_UPDATE", $response['body']['key']);
+ $this->assertEquals("TESTINGVALUEUPDATED", $response['body']['value']);
+
+ $variable = $this->client->call(Client::METHOD_GET, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $variable['headers']['status-code']);
+ $this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']);
+ $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']);
+
+ $response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertCount(1, $response['body']['variables']);
+ $this->assertEquals("APP_TEST_UPDATE", $response['body']['variables'][0]['key']);
+
+ /**
+ * Test for FAILURE
+ */
+
+ $response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(400, $response['headers']['status-code']);
+
+ $response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'value' => 'TESTINGVALUEUPDATED_2'
+ ]);
+
+ $this->assertEquals(400, $response['headers']['status-code']);
+
+ $longKey = str_repeat("A", 256);
+ $response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => $longKey,
+ 'value' => 'TESTINGVALUEUPDATED'
+ ]);
+
+ $this->assertEquals(400, $response['headers']['status-code']);
+
+ $longValue = str_repeat("#", 8193);
+ $response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => 'APP_TEST_UPDATE',
+ 'value' => $longValue
+ ]);
+
+ $this->assertEquals(400, $response['headers']['status-code']);
+
+ $response = $this->client->call(Client::METHOD_PUT, '/project/variables/NON_EXISTING_VARIABLE', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()), [
+ 'key' => 'APP_TEST_UPDATE',
+ 'value' => 'TESTINGVALUEUPDATED'
+ ]);
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+ return $data;
+ }
+
+ /**
+ * @depends testUpdateVariable
+ */
+ public function testDeleteVariable(array $data)
+ {
+ /**
+ * Test for SUCCESS
+ */
+
+ $response = $this->client->call(Client::METHOD_DELETE, '/project/variables/' . $data['variableId'], array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(204, $response['headers']['status-code']);
+
+ $response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertCount(0, $response['body']['variables']);
+ $this->assertEquals(0, $response['body']['total']);
+
+ /**
+ * Test for FAILURE
+ */
+
+ $response = $this->client->call(Client::METHOD_DELETE, '/project/variables/NON_EXISTING_VARIABLE', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $data['projectId'],
+ 'x-appwrite-mode' => 'admin',
+ ], $this->getHeaders()));
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+ return $data;
+ }
}
diff --git a/tests/e2e/Services/Realtime/RealtimeBase.php b/tests/e2e/Services/Realtime/RealtimeBase.php
index 30c411ba93..99f31134c0 100644
--- a/tests/e2e/Services/Realtime/RealtimeBase.php
+++ b/tests/e2e/Services/Realtime/RealtimeBase.php
@@ -7,25 +7,34 @@ use WebSocket\ConnectionException;
trait RealtimeBase
{
- private function getWebsocket($channels = [], $headers = [], $projectId = null): WebSocketClient
- {
+ private function getWebsocket(
+ array $channels = [],
+ array $headers = [],
+ string $projectId = null
+ ): WebSocketClient {
if (is_null($projectId)) {
$projectId = $this->getProject()['$id'];
}
- $headers = array_merge([
- 'Origin' => 'appwrite.test'
- ], $headers);
+ $headers = array_merge(
+ [
+ "Origin" => "appwrite.test",
+ ],
+ $headers
+ );
$query = [
- 'project' => $projectId,
- 'channels' => $channels
+ "project" => $projectId,
+ "channels" => $channels,
];
- return new WebSocketClient('ws://appwrite-traefik/v1/realtime?' . http_build_query($query), [
- 'headers' => $headers,
- 'timeout' => 30,
- ]);
+ return new WebSocketClient(
+ "ws://appwrite-traefik/v1/realtime?" . http_build_query($query),
+ [
+ "headers" => $headers,
+ "timeout" => 30,
+ ]
+ );
}
public function testConnection(): void
@@ -33,7 +42,7 @@ trait RealtimeBase
/**
* Test for SUCCESS
*/
- $client = $this->getWebsocket(['documents']);
+ $client = $this->getWebsocket(["documents"]);
$this->assertNotEmpty($client->receive());
$client->close();
}
@@ -43,11 +52,11 @@ trait RealtimeBase
$client = $this->getWebsocket();
$payload = json_decode($client->receive(), true);
- $this->assertArrayHasKey('type', $payload);
- $this->assertArrayHasKey('data', $payload);
- $this->assertEquals('error', $payload['type']);
- $this->assertEquals(1008, $payload['data']['code']);
- $this->assertEquals('Missing channels', $payload['data']['message']);
+ $this->assertArrayHasKey("type", $payload);
+ $this->assertArrayHasKey("data", $payload);
+ $this->assertEquals("error", $payload["type"]);
+ $this->assertEquals(1008, $payload["data"]["code"]);
+ $this->assertEquals("Missing channels", $payload["data"]["message"]);
\usleep(250000); // 250ms
$this->expectException(ConnectionException::class); // Check if server disconnnected client
$client->close();
@@ -55,18 +64,24 @@ trait RealtimeBase
public function testConnectionFailureUnknownProject(): void
{
- $client = new WebSocketClient('ws://appwrite-traefik/v1/realtime?project=123', [
- 'headers' => [
- 'Origin' => 'appwrite.test'
+ $client = new WebSocketClient(
+ "ws://appwrite-traefik/v1/realtime?project=123",
+ [
+ "headers" => [
+ "Origin" => "appwrite.test",
+ ],
]
- ]);
+ );
$payload = json_decode($client->receive(), true);
- $this->assertArrayHasKey('type', $payload);
- $this->assertArrayHasKey('data', $payload);
- $this->assertEquals('error', $payload['type']);
- $this->assertEquals(1008, $payload['data']['code']);
- $this->assertEquals('Missing or unknown project ID', $payload['data']['message']);
+ $this->assertArrayHasKey("type", $payload);
+ $this->assertArrayHasKey("data", $payload);
+ $this->assertEquals("error", $payload["type"]);
+ $this->assertEquals(1008, $payload["data"]["code"]);
+ $this->assertEquals(
+ "Missing or unknown project ID",
+ $payload["data"]["message"]
+ );
\usleep(250000); // 250ms
$this->expectException(ConnectionException::class); // Check if server disconnnected client
$client->close();
diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
index 6ab2874f8e..0155d251f2 100644
--- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
+++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
@@ -2,7 +2,6 @@
namespace Tests\E2E\Services\Realtime;
-use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
@@ -19,7 +18,7 @@ class RealtimeConsoleClientTest extends Scope
use ProjectCustom;
use SideConsole;
- public function testManualAuthentication()
+ public function testManualAuthentication(): void
{
$user = $this->getUser();
$userId = $user['$id'] ?? '';
@@ -124,7 +123,7 @@ class RealtimeConsoleClientTest extends Scope
$client->close();
}
- public function testAttributes()
+ public function testAttributes(): array
{
$user = $this->getUser();
$projectId = 'console';
@@ -184,6 +183,7 @@ class RealtimeConsoleClientTest extends Scope
'required' => true,
]);
+ $projectId = $this->getProject()['$id'];
$attributeKey = $name['body']['key'];
$this->assertEquals($name['headers']['status-code'], 202);
@@ -198,8 +198,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*.create", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -218,8 +219,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*.update", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -276,6 +278,8 @@ class RealtimeConsoleClientTest extends Scope
]);
$this->assertEquals($index['headers']['status-code'], 202);
+
+ $projectId = $this->getProject()['$id'];
$indexKey = $index['body']['key'];
$response = json_decode($client->receive(), true);
@@ -285,8 +289,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*.create", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -303,8 +308,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*.update", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -343,6 +349,8 @@ class RealtimeConsoleClientTest extends Scope
$this->assertContains('console', $response['data']['channels']);
$this->assertNotEmpty($response['data']['user']);
+ $projectId = $this->getProject()['$id'];
+
/**
* Test Delete Index
*/
@@ -353,6 +361,7 @@ class RealtimeConsoleClientTest extends Scope
], $this->getHeaders()));
$this->assertEquals($attribute['headers']['status-code'], 204);
+
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
@@ -360,8 +369,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*.update", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -377,8 +387,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*.delete", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -416,10 +427,12 @@ class RealtimeConsoleClientTest extends Scope
$this->assertContains('console', $response['data']['channels']);
$this->assertNotEmpty($response['data']['user']);
+ $attributeKey = 'name';
+ $projectId = $this->getProject()['$id'];
+
/**
* Test Delete Attribute
*/
- $attributeKey = 'name';
$attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/attributes/' . $attributeKey, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -433,8 +446,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*.update", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -450,8 +464,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*.delete", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}", $response['data']['events']);
@@ -463,6 +478,44 @@ class RealtimeConsoleClientTest extends Scope
$client->close();
}
+ public function testPing()
+ {
+ $client = $this->getWebsocket(['console'], [
+ 'origin' => 'http://localhost',
+ 'cookie' => 'a_session_console=' . $this->getRoot()['session'],
+ ], 'console');
+
+ $response = json_decode($client->receive(), true);
+
+ $this->assertArrayHasKey('type', $response);
+ $this->assertEquals('connected', $response['type']);
+
+ $pong = $this->client->call(Client::METHOD_GET, '/ping', [
+ 'origin' => 'http://localhost',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]);
+
+ $this->assertEquals(200, $pong['headers']['status-code']);
+ $this->assertEquals('Pong!', $pong['body']);
+
+ $response = json_decode($client->receive(), true);
+
+ $this->assertArrayHasKey('type', $response);
+ $this->assertEquals('event', $response['type']);
+ $this->assertNotEmpty($response['data']);
+ $this->assertArrayHasKey('timestamp', $response['data']);
+ $this->assertCount(2, $response['data']['channels']);
+ $this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$this->getProject()['$id']}", $response['data']['channels']);
+ $this->assertContains("projects.{$this->getProject()['$id']}.ping", $response['data']['events']);
+ $this->assertNotEmpty($response['data']['payload']);
+ $this->assertArrayHasKey('pingCount', $response['data']['payload']);
+ $this->assertArrayHasKey('pingedAt', $response['data']['payload']);
+ $this->assertEquals(1, $response['data']['payload']['pingCount']);
+
+ $client->close();
+ }
+
public function testCreateDeployment()
{
$response1 = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
@@ -505,22 +558,16 @@ class RealtimeConsoleClientTest extends Scope
/**
* Test Create Deployment
*/
-
- $folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
- $this->packageCode($folder);
-
+ $projectId = $this->getProject()['$id'];
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
- 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
+ 'code' => $this->packageFunction('php'),
'activate' => true
]);
- $deploymentId = $deployment['body']['$id'] ?? '';
-
$this->assertEquals(202, $deployment['headers']['status-code']);
$response = json_decode($client->receive(), true);
@@ -530,8 +577,9 @@ class RealtimeConsoleClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(1, $response['data']['channels']);
+ $this->assertCount(2, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$projectId}", $response['data']['channels']);
// $this->assertContains("functions.{$functionId}.deployments.{$deploymentId}.create", $response['data']['events']); TODO @christyjacob4 : enable test once we allow functions.* events
$this->assertNotEmpty($response['data']['payload']);
diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
index c3372b98c5..616f309fd2 100644
--- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
+++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
@@ -7,7 +7,7 @@ use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideClient;
-use Utopia\CLI\Console;
+use Tests\E2E\Services\Functions\FunctionsBase;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -15,6 +15,7 @@ use WebSocket\ConnectionException;
class RealtimeCustomClientTest extends Scope
{
+ use FunctionsBase;
use RealtimeBase;
use ProjectCustom;
use SideClient;
@@ -1271,20 +1272,13 @@ class RealtimeCustomClientTest extends Scope
$this->assertEquals($function['headers']['status-code'], 201);
$this->assertNotEmpty($function['body']['$id']);
- $folder = 'timeout';
- $stderr = '';
- $stdout = '';
- $code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz";
-
- Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
-
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'entrypoint' => 'index.php',
- 'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
+ 'code' => $this->packageFunction('timeout'),
'activate' => true
]);
@@ -1340,8 +1334,9 @@ class RealtimeCustomClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
- $this->assertCount(4, $response['data']['channels']);
+ $this->assertCount(5, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
+ $this->assertContains("projects.{$this->getProject()['$id']}", $response['data']['channels']);
$this->assertContains('executions', $response['data']['channels']);
$this->assertContains("executions.{$executionId}", $response['data']['channels']);
$this->assertContains("functions.{$functionId}", $response['data']['channels']);
@@ -1362,8 +1357,9 @@ class RealtimeCustomClientTest extends Scope
$this->assertEquals('event', $responseUpdate['type']);
$this->assertNotEmpty($responseUpdate['data']);
$this->assertArrayHasKey('timestamp', $responseUpdate['data']);
- $this->assertCount(4, $responseUpdate['data']['channels']);
+ $this->assertCount(5, $responseUpdate['data']['channels']);
$this->assertContains('console', $responseUpdate['data']['channels']);
+ $this->assertContains("projects.{$this->getProject()['$id']}", $response['data']['channels']);
$this->assertContains('executions', $responseUpdate['data']['channels']);
$this->assertContains("executions.{$executionId}", $responseUpdate['data']['channels']);
$this->assertContains("functions.{$functionId}", $responseUpdate['data']['channels']);
diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php
index 03dffac6aa..8a1fed028e 100644
--- a/tests/e2e/Services/Teams/TeamsBaseClient.php
+++ b/tests/e2e/Services/Teams/TeamsBaseClient.php
@@ -161,7 +161,7 @@ trait TeamsBaseClient
$this->assertNotEmpty($response['body']['userEmail']);
$this->assertNotEmpty($response['body']['teamId']);
$this->assertNotEmpty($response['body']['teamName']);
- $this->assertCount(2, $response['body']['roles']);
+ $this->assertCount(1, $response['body']['roles']);
$this->assertEquals(false, (new DatetimeValidator())->isValid($response['body']['joined'])); // is null in DB
$this->assertEquals(false, $response['body']['confirm']);
@@ -203,7 +203,7 @@ trait TeamsBaseClient
], $this->getHeaders()), [
'email' => $email,
'name' => $name,
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://localhost:5000/join-us#title'
]);
@@ -214,7 +214,7 @@ trait TeamsBaseClient
$this->assertEquals($email, $response['body']['userEmail']);
$this->assertNotEmpty($response['body']['teamId']);
$this->assertNotEmpty($response['body']['teamName']);
- $this->assertCount(2, $response['body']['roles']);
+ $this->assertCount(1, $response['body']['roles']);
$this->assertEquals(false, (new DatetimeValidator())->isValid($response['body']['joined'])); // is null in DB
$this->assertEquals(false, $response['body']['confirm']);
@@ -255,7 +255,7 @@ trait TeamsBaseClient
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'userId' => 'abcdefdg',
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://localhost:5000/join-us#title'
]);
@@ -270,7 +270,7 @@ trait TeamsBaseClient
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'userId' => $userId,
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://localhost:5000/join-us#title'
]);
@@ -281,7 +281,7 @@ trait TeamsBaseClient
$this->assertEquals($secondEmail, $response['body']['userEmail']);
$this->assertNotEmpty($response['body']['teamId']);
$this->assertNotEmpty($response['body']['teamName']);
- $this->assertCount(2, $response['body']['roles']);
+ $this->assertCount(1, $response['body']['roles']);
$this->assertEquals(false, (new DateTimeValidator())->isValid($response['body']['joined'])); // is null in DB
$this->assertEquals(false, $response['body']['confirm']);
@@ -301,7 +301,7 @@ trait TeamsBaseClient
], $this->getHeaders()), [
'email' => $email,
'name' => 'Friend User',
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://localhost:5000/join-us#title'
]);
@@ -313,7 +313,7 @@ trait TeamsBaseClient
], $this->getHeaders()), [
'email' => 'dasdkaskdjaskdjasjkd',
'name' => $name,
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://localhost:5000/join-us#title'
]);
@@ -337,7 +337,7 @@ trait TeamsBaseClient
], $this->getHeaders()), [
'email' => $email,
'name' => $name,
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://example.com/join-us#title' // bad url
]);
@@ -413,7 +413,7 @@ trait TeamsBaseClient
$this->assertNotEmpty($response['body']['$id']);
$this->assertNotEmpty($response['body']['userId']);
$this->assertNotEmpty($response['body']['teamId']);
- $this->assertCount(2, $response['body']['roles']);
+ $this->assertCount(1, $response['body']['roles']);
$this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['joined']));
$this->assertEquals(true, $response['body']['confirm']);
$session = $response['cookies']['a_session_' . $this->getProject()['$id']];
@@ -571,7 +571,7 @@ trait TeamsBaseClient
/**
* Test for SUCCESS
*/
- $roles = ['admin', 'editor', 'uncle'];
+ $roles = ['editor', 'uncle'];
$response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
@@ -587,7 +587,6 @@ trait TeamsBaseClient
$this->assertCount(count($roles), $response['body']['roles']);
$this->assertEquals($roles[0], $response['body']['roles'][0]);
$this->assertEquals($roles[1], $response['body']['roles'][1]);
- $this->assertEquals($roles[2], $response['body']['roles'][2]);
/**
* Test for unknown team
diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php
index 61d0f6a027..4b5ade7cbf 100644
--- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php
+++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php
@@ -28,12 +28,13 @@ class TeamsConsoleClientTest extends Scope
// Create a user account before we create a invite so we can check if the user has permissions when it shouldn't
$user = $this->client->call(Client::METHOD_POST, '/account', [
'content-type' => 'application/json',
- 'x-appwrite-project' => 'console'], [
- 'userId' => 'unique()',
- 'email' => $email,
- 'password' => $password,
- 'name' => $name,
- ], false);
+ 'x-appwrite-project' => 'console'
+ ], [
+ 'userId' => 'unique()',
+ 'email' => $email,
+ 'password' => $password,
+ 'name' => $name,
+ ], false);
$this->assertEquals(201, $user['headers']['status-code']);
@@ -46,7 +47,7 @@ class TeamsConsoleClientTest extends Scope
], $this->getHeaders()), [
'email' => $email,
'name' => $name,
- 'roles' => ['admin', 'editor'],
+ 'roles' => ['developer'],
'url' => 'http://localhost:5000/join-us#title'
]);
@@ -76,4 +77,75 @@ class TeamsConsoleClientTest extends Scope
return $data;
}
+
+ /** @depends testUpdateTeamMembership */
+ public function testUpdateTeamMembershipRoles($data): array
+ {
+ $teamUid = $data['teamUid'] ?? '';
+ $membershipUid = $data['membershipUid'] ?? '';
+ $session = $data['session'] ?? '';
+
+ /**
+ * Test for SUCCESS
+ */
+ $roles = ['developer'];
+ $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'roles' => $roles
+ ]);
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertNotEmpty($response['body']['$id']);
+ $this->assertNotEmpty($response['body']['userId']);
+ $this->assertNotEmpty($response['body']['teamId']);
+ $this->assertCount(count($roles), $response['body']['roles']);
+ $this->assertEquals($roles[0], $response['body']['roles'][0]);
+
+ /**
+ * Test for unknown team
+ */
+ $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . 'abc' . '/memberships/' . $membershipUid, array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'roles' => $roles
+ ]);
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+ /**
+ * Test for unknown membership ID
+ */
+ $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . 'abc', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'roles' => $roles
+ ]);
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+
+ /**
+ * Test for when a user other than the owner tries to update membership
+ */
+ $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
+ ], [
+ 'roles' => $roles
+ ]);
+
+ $this->assertEquals(401, $response['headers']['status-code']);
+ $this->assertEquals('User is not allowed to modify roles', $response['body']['message']);
+
+ return $data;
+ }
}
diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php
index d9105e0790..bd0a8ef937 100644
--- a/tests/e2e/Services/Users/UsersBase.php
+++ b/tests/e2e/Services/Users/UsersBase.php
@@ -1498,6 +1498,7 @@ trait UsersBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('random-email1@mail.org', $response['body']['identifier']);
+ $this->assertEquals(false, $response['body']['expired']);
return $response['body'];
}
@@ -1510,6 +1511,7 @@ trait UsersBase
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
+
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(3, \count($response['body']['targets']));
}
diff --git a/tests/extensions/Async.php b/tests/extensions/Async.php
new file mode 100644
index 0000000000..48af24bc02
--- /dev/null
+++ b/tests/extensions/Async.php
@@ -0,0 +1,17 @@
+waitMs * 1000);
+ } while (microtime(true) - $start < $this->timeoutMs / 1000);
+
+ if ($returnResult) {
+ return false;
+ }
+
+ throw $lastException;
+ }
+
+ protected function failureDescription(mixed $other): string
+ {
+ return 'the given probe was satisfied within ' . $this->timeoutMs . 'ms.';
+ }
+
+ public function toString(): string
+ {
+ return 'Eventually';
+ }
+}
diff --git a/tests/unit/Utopia/ResponseTest.php b/tests/unit/Utopia/ResponseTest.php
index cd111ec22c..452119fafb 100644
--- a/tests/unit/Utopia/ResponseTest.php
+++ b/tests/unit/Utopia/ResponseTest.php
@@ -55,12 +55,32 @@ class ResponseTest extends TestCase
'integer' => 123,
'boolean' => true,
'hidden' => 'secret',
+ 'array' => [
+ 'string 1',
+ 'string 2'
+ ],
]), 'single');
$this->assertArrayHasKey('string', $output);
$this->assertArrayHasKey('integer', $output);
$this->assertArrayHasKey('boolean', $output);
$this->assertArrayNotHasKey('hidden', $output);
+ $this->assertIsArray($output['array']);
+
+ // test optional array
+ $output = $this->response->output(new Document([
+ 'string' => 'lorem ipsum',
+ 'integer' => 123,
+ 'boolean' => true,
+ 'hidden' => 'secret',
+ ]), 'single');
+ $this->assertArrayHasKey('string', $output);
+ $this->assertArrayHasKey('integer', $output);
+ $this->assertArrayHasKey('boolean', $output);
+ $this->assertArrayNotHasKey('hidden', $output);
+ $this->assertArrayHasKey('array', $output);
+ $this->assertNull($output['array']);
+
}
public function testResponseModelRequired(): void
diff --git a/tests/unit/Utopia/Single.php b/tests/unit/Utopia/Single.php
index 3bd09ef6da..b7f36d10a8 100644
--- a/tests/unit/Utopia/Single.php
+++ b/tests/unit/Utopia/Single.php
@@ -28,6 +28,11 @@ class Single extends Model
'type' => self::TYPE_STRING,
'default' => 'default',
'required' => true
+ ])
+ ->addRule('array', [
+ 'type' => self::TYPE_STRING,
+ 'required' => false,
+ 'array' => true,
]);
}